Skip to main content
Glama

CI Gitleaks Trivy GitHub Release npm OpenSSF Scorecard OpenSSF Best Practices Ask DeepWiki vault-cortex MCP server

Vault Cortex — это автономный MCP-сервер, который даёт любому ИИ-агенту гибридный поиск, управление задачами, структурированную память и доступ на чтение и запись к вашему хранилищу Obsidian. Никаких плагинов, запущенного Obsidian или отдельного моста. Один Docker-контейнер, ваша папка хранилища, полный набор инструментов и управляющие подсказки. Запустите его на удалённом сервере с Obsidian Sync — и то же хранилище будет доступно с телефона, claude.ai или любого удалённого MCP-клиента, защищённое OAuth 2.1. Разверните в один клик или разместите у себя; в любом случае хранилище всегда остаётся вашим.

СодержаниеЧто вы получаете · Быстрый старт · Как это работает · Гибридный поиск · Память · Задачи · Файлы · Инструменты · Подсказки · Свойства · Конфигурация · Ежедневные заметки · Целостность данных · Аутентификация · Варианты развёртывания · Развёртывание в один клик · Развёртывания сообщества

Что вы получаете

  • Удалённый доступ — работает с телефона, удалённого сервера или любого MCP-клиента через OAuth 2.1. Один клик на Render или Railway — и всё готово, без необходимости управлять сервером; VPS тоже подойдёт.

  • Без плагинов — Obsidian не должен быть запущен. Сервер работает напрямую с .md-файлами на диске. Headless-синхронизация поддерживает хранилище в актуальном состоянии.

  • Гибридный поиск — ключевое соответствие FTS5 + векторное семантическое сходство через RRF-слияние, уточняемое кросс-энкодерным реранкингом для запросов с высокой смысловой нагрузкой. Ключевые слова остаются точными для конкретных терминов и жаргона; векторы находят заметки, даже когда ваши слова отличаются от слов в хранилище.

  • Структурированная память — датированные, только добавляемые записи накапливаются в личный слой знаний, автоматически инициализируемый для персонализации ИИ. Воспоминание по теме отвечает на вопрос «что я думаю об X?» с текущей позицией и датированной историей за ней — включая эволюцию.

  • Задачи — запросы и обновления задач с поддержкой канбана: триаж по статусу, датам или приоритету, затем завершение, изменение приоритета или перемещение задач между колонками одним вызовом. Разбирает как эмодзи плагина Tasks, так и форматы инлайн-полей Dataview.

  • Граф ссылок — обратные ссылки, исходящие ссылки и обнаружение сирот по всему хранилищу

  • Файлы — чтение и немаркдаун-файлов хранилища: изображения приходят как настоящие изображения (при необходимости уменьшенные), PDF — как структурированный текст или отрисованные страницы, канвасы — как читаемые планы, файлы данных — как текст

  • Нативный Obsidian — понимает frontmatter, вики-ссылки, теги, заголовки и ежедневные заметки

  • Управляемые рабочие процессы — встроенные подсказки для проверки здоровья хранилища, обзора памяти и ежедневной сверки — каждый раз собираются из живых данных хранилища

Протестировано во время 15-дневной поездки по Европе. 30+ сессий с телефона, 216 вызовов инструментов, ни разу не понадобился ноутбук. Записи из одной сессии были немедленно доступны в следующей, в разных городах и днях.


Related MCP server: Vault MCP Server (mschuchard)

Быстрый старт

Локально (2 минуты — Docker + ваша папка хранилища)

Предварительные требования: Docker (или совместимая с Docker среда, например OrbStack, Colima, Podman), Node.js >= 20.12 (только для CLI — сам сервер работает в Docker) и хранилище Obsidian (или любая папка с .md-файлами).

npx vault-cortex@latest init

Вот и всё — CLI запросит путь к хранилищу, сгенерирует токен аутентификации и файлы конфигурации, запустит сервер и выведет данные для подключения вашего MCP-клиента (справочник CLI →).

npx vault-cortex@latest init — интерактивный мастер настройки выбирает режим, находит ваше хранилище, предлагает дополнительные параметры, генерирует конфигурацию и запускает сервер

Настроили через CLI? Он и дальше управляет сервером — configure, upgrade, start, restart, logs, down (справочник CLI →).

Настроили через Compose? Для обновлений тоже используйте Compose (docker compose pull && docker compose up -d) — CLI и Compose управляют контейнером независимо.

# 1. Get the quickstart files
curl -O https://raw.githubusercontent.com/aliasunder/vault-cortex/main/deploy/local/docker-compose.yml
curl -O https://raw.githubusercontent.com/aliasunder/vault-cortex/main/deploy/local/.env.example

# 2. Configure
cp .env.example .env
# Edit .env — set MCP_AUTH_TOKEN (openssl rand -hex 32) and VAULT_PATH

# 3. Start
docker compose up

Полное локальное руководство → (включая настройку для Windows)

Удалённо (доступ откуда угодно)

Ваше хранилище на сервере, поддерживаемое в актуальном состоянии Obsidian Sync, доступное с телефона, claude.ai или любого MCP-клиента. Варианты в один клик запрашивают токен Obsidian Sync, имя хранилища и часовой пояс (плюс пароль хранилища, если оно зашифровано), затем берут на себя HTTPS, перезапуски, сгенерированный MCP-токен и постоянное хранилище для самого хранилища и его индекса. На собственном сервере CLI запрашивает публичный URL и имя хранилища, перехватывает токен Sync за вас и генерирует MCP-токен; настройка HTTPS — ваша задача.

Railway

Render

Self-hosted

Deploy on Railway

Deploy to Render

Настройка через CLI →

Аккаунт

Railway на тарифе Hobby или выше — том на 5 ГБ включён

Render с привязанной картой

VPS с Docker

Стоимость

По использованию: обычно $20–30 USD/мес для личного хранилища — чуть меньше Render для тихого хранилища, чуть больше для активного

Фиксированная: около $26 USD/мес для стандартного инстанса (2 ГБ) и 5 ГБ диска, оплата посекундно

Сколько стоит ваш VPS

Выбирайте, если

Хотите более лёгкий старт — шаблон сразу приводит вас в настроенный проект

Предсказуемый счёт важнее удобства настройки

Уже запускаете сервер или хотите полный контроль

Руководство

Руководство по Railway →

Руководство по Render →

Руководство по удалённому развёртыванию →

Всем трём нужна подписка Obsidian Sync. Что бы вы ни выбрали, сервер заменяем, а ваше хранилище — нет: оно остаётся в обычном Markdown в Obsidian Sync и на ваших устройствах; контейнер хранит только копию.

Self-hosted: ваш собственный VPS

CLI vault-cortex настраивает тот же контейнер на любом Linux-сервере, которым вы управляете, — вы управляете сервером, образом и обновлениями. Для самого CLI нужен Node.js >= 20.12; сервер работает в Docker.

# On your VPS:
npx vault-cortex@latest init --mode remote

Вот и всё — CLI проведёт вас через публичный URL, токен Obsidian Sync (он может запустить get-sync-token за вас), имя хранилища, пароль хранилища для зашифрованного хранилища и конфигурацию аутентификации, затем запустит сервер (справочник CLI →).

Настроили через CLI? Он и дальше управляет сервером — configure, upgrade, start, restart, logs, down (справочник CLI →).

Настроили через Compose? Для обновлений тоже используйте Compose (docker compose pull && docker compose up -d) — CLI и Compose управляют контейнером независимо.

# On your VPS:
mkdir -p /opt/vault-cortex && cd /opt/vault-cortex
curl -O https://raw.githubusercontent.com/aliasunder/vault-cortex/main/deploy/remote/docker-compose.yml
curl -O https://raw.githubusercontent.com/aliasunder/vault-cortex/main/deploy/remote/.env.example
cp .env.example .env
# Edit .env — set MCP_AUTH_TOKEN, PUBLIC_URL, OBSIDIAN_AUTH_TOKEN, VAULT_NAME
docker compose up -d

Подключите ваш MCP-клиент

Настройка

URL сервера

Локальная

http://localhost:8000/mcp

Удалённая (в один клик)

https://<host>/mcp<host> — это домен, который Render или Railway показывает на странице сервиса

Удалённая (самостоятельно)

<PUBLIC_URL>/mcp

Добавьте URL сервера в любой MCP-клиент — Claude Code, Claude Desktop, Cursor, OpenCode или любой другой. OAuth-клиенты открывают страницу согласия в вашем браузере — подтвердите своим токеном, и клиент возьмёт на себя продление токена с этого момента. Клиенты без OAuth (MCP Inspector, скрипты) отправляют токен напрямую в заголовке Authorization: Bearer.

Claude Code:

claude mcp add --scope user --transport http vault-cortex http://localhost:8000/mcp   # local (or <PUBLIC_URL>/mcp)

--scope user регистрирует сервер для всех проектов; опустите этот флаг, чтобы ограничить его только текущей директорией.

Диалог «Add custom connector» принимает только URL с https. Если у вас https PUBLIC_URL, добавьте его напрямую в диалоге коннектора; для локального сервера зарегистрируйте его в claude_desktop_config.json через stdio-мост mcp-remote:

{
  "mcpServers": {
    "vault-cortex": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote",
        "http://localhost:8000/mcp",
        "--header",
        "Authorization: Bearer <your MCP_AUTH_TOKEN>"
      ]
    }
  }
}

claude.ai (веб и мобильный) подключается только к удалённой настройке — его коннекторы загружаются на стороне сервера и никогда не могут достичь localhost.

«Удалённый MCP-сервер» относится к типу подключения (HTTP) — в локальной настройке сервер по-прежнему полностью работает на вашей машине.

См. Аутентификация — оба метода и сроки жизни токенов.


Как это работает

Всё работает в одном Docker-контейнере, напрямую с .md-файлами на диске:

  • Ваше хранилище остаётся источником истины — сервер читает и записывает те же обычные Markdown-файлы, что и ваши приложения Obsidian.

  • Поиск — это производные данные — файловый наблюдатель поддерживает индекс (ключевые слова + векторы) в актуальном состоянии по мере изменения заметок, и его можно пересобрать из ваших заметок в любой момент.

  • Удалённый образ добавляет цикл синхронизации — встроенный сервис Obsidian Sync поддерживает хранилище контейнера в актуальном состоянии на каждом устройстве: отредактируйте заметку на телефоне — и она станет доступна для поиска через мгновение; агент записывает заметку — и она появляется в Obsidian.

graph LR
    subgraph container ["One Docker container"]
        Sync["sync service<br/>(remote image)"]
        Vault[("/vault<br/>.md files — source of truth")]
        Index[("search index<br/>keywords + vectors")]
        Server["MCP server"]
        Sync <-->|read/write| Vault
        Vault -->|file watcher| Index
        Server <-->|read/write| Vault
        Server -->|query| Index
    end
    Obsidian["Your Obsidian apps<br/>(phone, laptop)"] <-->|Obsidian Sync| Sync
    Client["Any MCP client<br/>(Claude, Cursor, claude.ai)"] -->|OAuth 2.1 / Bearer| Server

Полное описание архитектуры, схемы потоков аутентификации и разбивку компонентов см. в ARCHITECTURE.md.


Гибридный поиск

Поиск только по ключевым словам даёт сбой, когда ваш словарный запас не совпадает со словарём хранилища — «стремления» не найдут заметку о «целях», «коллеги» не всплывут в вашем файле «контакты». При тестировании на реальном хранилище 30% запросов на естественном языке возвращали ноль или нерелевантные результаты при поиске только по ключевым словам. Гибридный поиск устранил эти промахи — векторы преодолевают словарный разрыв, а реранкер спасает запросы с сильной интенцией, где ни один из сигналов по отдельности недостаточно силён.

Гибридный поиск объединяет три сигнала ранжирования через Reciprocal Rank Fusion:

  • Ключевые слова (FTS5) остаются точными для конкретных терминов, жаргона и значений свойств

  • Векторы (sqlite-vec) преодолевают словарный разрыв, сопоставляя по смыслу

  • Реранкер (cross-encoder) уточняет порядок, оценивая каждую пару запрос-документ совместно — спасает запросы с сильной интенцией, где и ключевые слова, и векторы промахиваются

Все модели работают локально (~45MB суммарно, без внешних API). Установите EMBEDDING_ENABLED=false для поиска только по ключевым словам или RERANK_MODE=none, чтобы пропустить реранкинг ради меньшей задержки.

Подробности о моделях, весах смешивания и полной схеме конвейера см. в ARCHITECTURE.md → Гибридный поиск.


Память

Слой памяти, который только растёт, полезен лишь в том случае, если агенты могут извлекать нужные записи, не сваливая всё в контекст. Когда у вас есть сотни датированных записей в нескольких файлах — предпочтения, принципы, стиль общения, текущие обязательства — чтение целых файлов тратит контекст на нерелевантный материал и засоряет сигнал. Система памяти спроектирована для точечного извлечения: агенты накапливают знания со временем и вспоминают ровно то, что относится к текущей задаче.

Слой — это папка с обычными Markdown-файлами (по умолчанию: About Me/), содержащими датированные записи под тематическими заголовками — автоматически создаётся со стартовыми шаблонами при первом запуске, пополняется агентами через vault_update_memory. Три свойства обеспечивают его работу:

  • Только добавление — записи никогда не перезаписываются; исправления приходят как новые датированные записи. Слой становится личной базой знаний, которая фиксирует ваше текущее состояние и историю его развития

  • Тематическое извлечениеvault_memory_recall извлекает все релевантные записи из всех файлов памяти сразу, по ключевым словам и по смыслу, от старых к новым. Спросите «что я думаю об X?» — и получите текущую позицию плюс датированную историю её развития — без чтения целых файлов и угадывания, в каком файле что лежит

  • Растёт без деградации — ограничение результатов (max_results) отбрасывает наименее релевантные записи, а не срез временной шкалы. Слой памяти с 500 записями обслуживает точечный запрос так же хорошо, как и с 50

Файлы, описывающие текущее состояние, а не то, что было верно раньше (рутины, активные обязательства), могут объявить entry-policy: living во frontmatter — их устаревшие записи можно вычищать, а не сохранять, что сохраняет точность картины текущего состояния.

Весь слой опционален — установите MEMORY_ENABLED=false, чтобы скрыть инструменты памяти и полностью пропустить автоматическое создание папки.

См. ARCHITECTURE.md → Память — конвейер извлечения, модель индексации, автоматическую инициализацию и поведение при отключении, а также templates/memory — формат файлов, соглашение entry-policy и стартовые шаблоны.


Задачи

Метаданные задач живут в обычном markdown — разбросаны по файлам, закодированы в эмодзи-символах или инлайн-полях, организованы под заголовками канбана. Агенту, отвечающему на вопрос «что просрочено?», пришлось бы разбирать каждый файл и понимать ваш выбранный формат; завершение задачи на канбан-доске означает знание структуры колонок доски, синтаксиса дат и того, какой заголовок является колонкой «готово».

Слой задач берёт это на себя, чтобы агентам не приходилось:

  • Находить — фильтрация по статусу, шести полям дат (срок, запланировано, начало, создано, выполнено, отменено), приоритету, папке или колонке канбана. Каждый результат несёт свою колонку, путь к заметке, заголовок и номер строки — никаких дополнительных чтений для поиска задачи

  • Обновлять — завершать, менять приоритет и перемещать задачи между колонками канбана одним вызовом. Отметка задачи как выполненной автоматически определяет колонку «готово» и проставляет дату завершения; отмена — удаляет дату. Все три изменения могут произойти одновременно

  • Оба формата — какой бы формат вы ни использовали, эмодзи-символы плагина Tasks или инлайн-поля Dataview, сервер читает оба и записывает в том формате, под который настроен ваш плагин Tasks

См. ARCHITECTURE.md → Задачи — модель индексации, каскадную сортировку по датам и определение колонок канбана.


Файлы

Ваши заметки содержат скриншоты, ссылки на диаграммы архитектуры и ведут на канвасы и файлы данных — но для агента, читающего markdown, ![[diagram.png]] — просто текст. vault-cortex относится к файлам как к части хранилища, а не как к мусору вокруг него — связанные, с размерами и читаемые, каждая в той форме, которую агент реально может использовать:

  • Изображения — само изображение, а не имя файла. Скриншоты и диаграммы уменьшаются и пережимаются на стороне сервера, когда превышают то, что принимают MCP-клиенты, так что даже мобильная сессия может посмотреть 5MB диаграмму архитектуры

  • Канвасы — доска Canvas приходит как читаемый план: её группы, содержимое каждой карточки в порядке чтения и связи между ними. Содержимое канваса полнотекстово индексируется, а ссылки на файлы на доске появляются в графе связей — обратные и исходящие ссылки работают так же, как ссылки между заметками. Точный JSON-исходник — в одном флаге, когда важна полная точность

  • PDF — текст извлекается с сохранением иерархии заголовков, блоков кода и гиперссылок; содержимое PDF полнотекстово индексируется наравне с вашими заметками. Установите raw: true, чтобы вместо этого отображать страницы как изображения, показывая вёрстку, диаграммы и таблицы, которые текстовая экстракция не сохраняет — сканы и PDF только с изображениями работают в этом режиме

  • Текстовые и файлы данных — TXT, SVG, JSON, XML, CSV, YAML, логи и файлы Bases возвращаются ровно как написаны; первые 100 КБ содержимого полнотекстово индексируются. Большие файлы данных и логи можно читать по диапазонам строк, при этом каждая страница сообщает, где вы находитесь и сколько файла осталось

  • Просмотр — список файлов любой видимой папки с количеством по расширениям и размерами файлов; файлы, на которые ссылается заметка, также сообщают свой размер в графе связей

Установите FILE_TOOLS_ENABLED=false, чтобы скрыть файловые инструменты — полезно, когда ваше удалённое хранилище синхронизируется без вложений.

См. ARCHITECTURE.md → Файлы — конвейер обработки изображений и модель диспетчеризации.


Инструменты

Категория

Инструмент

Описание

CRUD хранилища

vault_read_note

Прочитать заметку — полный текст, свойства, структуру или раздел

vault_write_note

Создать заметку (завершается ошибкой, если она уже существует; установите overwrite для замены)

vault_patch_note

Редактирование по заголовкам (добавление в конец, в начало, замена с защитой include_children, вставка)

vault_replace_in_note

Поиск и замена текста в заметке (первое совпадение или replace_all_occurrences)

vault_delete_span

Удалить блок строк по коротким якорям без полного повторного цитирования

vault_list_notes

Список заметок с необязательным фильтром по glob/папке

vault_delete_note

Удалить заметку (защищённые пути соблюдаются)

vault_move_note

Переместить или переименовать заметку с перезаписью ссылок по всему хранилищу

Поиск

vault_search

Гибридный поиск с фильтрами по тегам/папкам/свойствам/датам

vault_search_by_tag

Найти заметки по тегу (точное или префиксное совпадение)

vault_search_by_folder

Просмотр заметок в папке с метаданными

vault_recent_notes

Недавно изменённые или созданные заметки

vault_list_tags

Все теги с количеством использований

Задачи

vault_list_tasks

Индекс задач по всему хранилищу — с поддержкой Kanban, 6 полей дат, приоритет, область по папкам/заголовкам

vault_update_task

Изменение статуса, приоритета и колонок одним вызовом — автоматически определяет завершённые колонки на Kanban-досках

Память

vault_get_memory

Прочитать структурированную память (файл, раздел или всё)

vault_update_memory

Добавить запись с датой в раздел памяти

vault_delete_memory

Удалить конкретную запись памяти по дате

vault_list_memory_files

Обнаружить файлы памяти, их разделы и политику записей каждого файла

vault_memory_recall

Гибридный поиск по теме на уровне записей по файлам памяти, от старых к новым

Свойства

vault_list_property_keys

Все ключи свойств с примерами значений

vault_list_property_values

Уникальные значения для ключа свойства

vault_search_by_property

Найти заметки по паре ключ-значение свойства

vault_update_properties

Добавить или обновить свойства, не затрагивая тело заметки

Ссылки

vault_get_backlinks

Заметки, ссылающиеся на указанный путь

vault_get_outgoing_links

Ссылки из указанной заметки

vault_find_orphans

Заметки без входящих ссылок

Файлы

vault_read_file

Прочитать файл не в формате Markdown — изображения передаются как изображения, канвасы как читаемые структуры

vault_list_files

Просмотр файлов хранилища не в формате Markdown с размерами и количеством по расширениям

Ежедневные заметки

vault_get_daily_note

Ежедневная заметка на сегодня (или любую дату)


Промпты

Инструменты управляются моделью — их вызывает ассистент. Промпты — это рабочие процессы, которые запускаете вы. Каждый из них обращается к поисковому индексу, графу ссылок и слою памяти в момент вызова, а затем собирает результаты с направляющими инструкциями — так сессия начинается с опорой на реальное состояние вашего хранилища, а не на предположения.

Промпт

Аргументы

Что делает

vault-orientation

Обозревает статистику хранилища, распределение папок, уровень использования свойств (отмечает низкое использование), сирот, количество битых ссылок, теги, недавние заметки и слой памяти — с контекстными подсказками по инструментам

memory-review

file?, max_chars?

Структурный обзор (callout-блоки области, количество записей в разделах) + датированное содержимое в виде хронологии. Направляемая рефлексия: повествование об эволюции, соответствие области, заполнение пробелов и анализ покрытия — по умолчанию только добавление, сокращение предлагается только для файлов с entry-policy: living. Скрыт, когда MEMORY_ENABLED=false, READONLY_MODE=true или DISABLED_TOOLS включает vault_update_memory.

daily-review

date?, max_chars?

Сверяет день — ежедневную заметку, статус задач по всему хранилищу (срок/просрочено, запланировано), изменённые заметки, исходящие ссылки (обнаружение битых ссылок) и обратные ссылки — показывает, что произошло, что осталось открытым и что требует продолжения

Промпты адаптируются к вашей конфигурации (MEMORY_DIR, настройки ежедневных заметок) и работают с любым хранилищем из коробки. Передайте max_chars, чтобы ограничить встроенное содержимое, если ваш клиент имеет лимиты на размер полезной нагрузки.

Поддержка клиентов: Промпты работают в Claude Desktop (Chat и Cowork — через меню + в вашем коннекторе), Claude Code (слэш-команды) и OpenCode. Поддержка в других клиентах (Cursor, Windsurf) различается — см. матрицу MCP-клиентов для актуальной информации.


Свойства

Vault Cortex индексирует каждое свойство в ваших заметках, но пять получают повышенный статус — выделенные колонки для быстрой фильтрации и поля верхнего уровня в каждом результате поиска и обнаружения:

Свойство

Что можно делать

title

Отображаемое имя в результатах поиска; при отсутствии используется имя файла

tags

Поиск и фильтрация по тегу, включая иерархии родитель-потомок (project соответствует project/vault-cortex)

type

Фильтр по типу заметки — meeting, person, session-log или любое значение, используемое в вашем хранилище

created

Сортировка по дате создания и просмотр даты создания каждой заметки рядом с каждым результатом поиска

related

Фильтр заметок, перекрёстно ссылающихся на конкретную ссылку — выявляет связи, невидимые без графового запроса

Все остальные свойства по-прежнему полностью доступны для запросов — используйте vault_search с filters.properties для комбинированных запросов по тексту и метаданным, или vault_search_by_property для поиска только по метаданным. vault_list_property_keys и vault_list_property_values позволяют узнать, какие свойства существуют в вашем хранилище.

Это соглашения, а не требования — Vault Cortex работает с любой схемой свойств. Повышенные свойства просто дают более богатую фильтрацию и более чистые результаты из коробки.

Ведущие callout-блоки обрабатываются так же. Когда первое содержимое тела заметки — это Obsidian callout (> [!type]) — сразу после frontmatter или сразу после заголовка — он индексируется и отображается рядом с каждым результатом обнаружения (в vault_search запросите его с помощью include_leading_callout). Это делает заметки самоописывающими: агент, просматривающий результаты, может увидеть, для чего предназначена каждая заметка, прежде чем решить, какую читать. Шаблоны памяти используют callout-блоки > [!info] Scope of this file для этого, и любая заметка в вашем хранилище может использовать тот же шаблон.


Конфигурация

Все настройки — это переменные окружения с разумными значениями по умолчанию. Удалённые развёртывания также передают собственные настройки Obsidian Sync — DEVICE_NAME, SYNC_MODE, CONFLICT_STRATEGY, SYNC_CONFIGS, SYNC_EXCLUDED_FOLDERS, SYNC_FILE_TYPES — описанные в таблице конфигурации руководства по удалённому развёртыванию.

Переменная

Обязательная?

По умолчанию

Описание

MCP_AUTH_TOKEN

Да

Bearer-токен для аутентификации (также ключ подписи JWT)

VAULT_PATH

Только локально

Путь на хосте к вашему хранилищу (источник bind-mount; удалённо используется именованный том)

PUBLIC_URL

Только удалённо

Публичный URL для метаданных обнаружения OAuth. Заполняется автоматически на Render и Railway (из RENDER_EXTERNAL_URL или RAILWAY_PUBLIC_DOMAIN), если не задан

OBSIDIAN_AUTH_TOKEN

Только удалённо

Токен аутентификации Obsidian Sync — CLI-инструмент get-sync-token получит его за вас

VAULT_NAME

Только удалённо

Точное имя вашего хранилища Obsidian Sync (с учётом регистра)

VAULT_PASSWORD

Только удалённо

Пароль сквозного шифрования, если он есть у вашего хранилища. В противном случае оставьте пустым.

STORAGE_ROOT

Единый каталог для всего, что должно сохраняться — хранилища, поискового индекса и состояния Obsidian Sync — для платформ контейнерного хостинга, допускающих один постоянный том (Railway, Render). Подключите том туда и укажите этот же путь

EMBEDDING_ENABLED

true

Установите false, чтобы отключить конвейер эмбеддингов — пропускается загрузка модели, векторные таблицы, проходы эмбеддингов и гибридный поиск. Поиск переключается на ключевое сопоставление FTS5.

RERANK_MODE

blended

Режим переранжирования кросс-энкодером: blended применяет смешивание оценок с учётом позиции после слияния RRF (добавляет ~200 мс задержки), none пропускает переранжирование. Действует только при EMBEDDING_ENABLED = true.

MEMORY_ENABLED

true

Установите false, чтобы полностью отключить слой памяти — скрывает инструменты памяти, пропускает начальную загрузку, исключает память из метаданных сервера. MEMORY_DIR игнорируется при false.

FILE_TOOLS_ENABLED

true

Установите false, чтобы скрыть файловые инструменты (vault_read_file, vault_list_files) — полезно для удалённых развёртываний, где синхронизация вложений Obsidian Sync отключена.

READONLY_MODE

false

Установите true, чтобы скрыть все инструменты, изменяющие хранилище, и пропустить автоматическое создание папки памяти — подключённые клиенты смогут читать и искать, но не редактировать.

DISABLED_TOOLS

Скрывает отдельные инструменты по имени, через запятую (например, vault_delete_note,vault_move_note). Имена соответствуют столбцу Name в таблице инструментов. Только вычитающий — не может повторно включить инструмент, скрытый другой настройкой. Неизвестное имя инструмента останавливает сервер при запуске, поэтому опечатки обнаруживаются сразу.

MEMORY_DIR

About Me

Папка хранилища для структурированных файлов памяти

PROTECTED_PATHS

MEMORY_DIR, DAILY_NOTES_FOLDER

Папки, которые vault_delete_note отказывается трогать

ORPHAN_EXCLUDE_FOLDERS

DAILY_NOTES_FOLDER, Templates, MEMORY_DIR

Папки, исключённые из обнаружения осиротевших заметок

DAILY_NOTES_FOLDER

из конфигурации хранилища

Задаёт папку, в которой находятся ваши ежедневные заметки. Если не задано, читается из .obsidian/daily-notes.json хранилища с запасным вариантом Daily Notes. См. Ежедневные заметки.

DAILY_NOTES_FORMAT

из конфигурации хранилища

Задаёт формат имени файла ежедневной заметки — те же токены, что и в настройке формата даты ежедневных заметок Obsidian. Если не задано, читается из .obsidian/daily-notes.json хранилища с запасным вариантом YYYY-MM-DD. См. Ежедневные заметки.

TZ

UTC

Часовой пояс IANA для временных меток и определения ежедневных заметок

SERVICE_DOCUMENTATION_URL

URL репозитория GitHub

URL, возвращаемый в метаданных обнаружения OAuth

LOG_LEVEL

info

Подробность журналирования: debug, info, warn, error

LOG_DIR

/data/logs (удалённо), $STORAGE_ROOT/data/logs (один том), none (локально)

Каталог для файлов журнала, переживающих пересоздание контейнера. Собственный журнал контейнера (то, что показывает docker logs) записывается всегда, но Docker отбрасывает его при каждом пересоздании контейнера — при обновлении образа или изменении конфигурации. Файлы с датами в имени под LOG_DIR хранятся на томе данных и сохраняются. none оставляет только журнал контейнера.

LOG_RETENTION_DAYS

90

Сколько дней хранить файлы журнала до автоматической очистки при запуске; применяется только когда LOG_DIR — это путь

WINDOWS_MODE

false

На Windows? Установите true. Переключает наблюдатель файлов на опрос, а перемещение заметок — на запись через переименование, чтобы хранилище на диске C: работало через Docker Desktop. Можно безопасно оставить включённым для любой настройки Windows; не требуется на macOS/Linux/WSL2.

MAX_FILE_BYTES

52428800 (50 МиБ)

Максимальный размер файла, который прочитает vault_read_file (в байтах). Файлы, превышающие это значение, отклоняются до чтения. Увеличьте для хранилищ с очень большими отдельными файлами.

MAX_IMAGE_OUTPUT_BYTES

49152 (48 КиБ)

Бюджет байтов для изображений, возвращаемых vault_read_file, в двоичных байтах до кодирования base64. Изображения, превышающие это значение, уменьшаются и пережимаются, чтобы вписаться. Подобрано под самый строгий лимит массовых MCP-клиентов; увеличьте для клиентов, принимающих большие ответы.

MAX_PDF_RENDER_PAGES

5

Максимальное количество страниц PDF, отображаемых как изображения, когда для vault_read_file задано raw: true. Побайтовый бюджет на страницу — это MAX_IMAGE_OUTPUT_BYTES, разделённый поровну между отображаемыми страницами — меньше страниц означает выше качество каждой.

TRUST_PROXY_HOPS

0

Количество доверенных переходов обратного прокси, используемых для определения IP клиента из X-Forwarded-For (ограничение частоты OAuth, журналы запросов). Установите 1, когда перед сервером стоит ровно один контролируемый вами прокси (Caddy, nginx, Cloudflare Tunnel, API Gateway). При 0 внедрённые заголовки пересылки игнорируются.

TRUST_FORWARDED_HOPS

0

Сколько завершающих записей for= в заголовке Forwarded по RFC 7239 принадлежат контролируемым вами прокси. 0 игнорирует заголовок; 1 — когда его записывает прокси перед сервером (например, AWS API Gateway); 2 — когда перед этим прокси стоит CDN и это единственный способ доступа к нему.

  • Умные значения по умолчанию — установка MEMORY_DIR или DAILY_NOTES_FOLDER автоматически обновляет значения по умолчанию для PROTECTED_PATHS и ORPHAN_EXCLUDE_FOLDERS; когда DAILY_NOTES_FOLDER не задан, Daily Notes занимает его место. Папка ежедневных заметок, настроенная только в daily-notes.json, не подхватывается — добавьте её в PROTECTED_PATHS самостоятельно. Вы задаёте их явно только для полностью настраиваемого списка.

  • MEMORY_ENABLED=false полностью отключает слой памяти — инструменты памяти скрыты, а папка памяти не создаётся автоматически.

  • FILE_TOOLS_ENABLED=false полностью скрывает файловые инструменты — полезно, когда в Obsidian Sync отключена синхронизация вложений и на диске нет файлов.

  • READONLY_MODE=true скрывает все инструменты записи в хранилище и пропускает автоматическое создание папки памяти — подключённые клиенты могут читать и искать, но никогда не редактировать.

  • DISABLED_TOOLS скрывает ровно те инструменты, которые вы назвали — для более тонкого контроля, чем переключатели выше, например, оставить запись включённой, но удалить vault_delete_note и vault_move_note. Перекрёстные ссылки по доступности в описаниях инструментов и подсказках корректируются автоматически.

См. templates/memory/ для примеров файлов памяти и философии датированных записей.

Ежедневные заметки

vault_get_daily_note и подсказка ежедневного обзора находят ваши ежедневные заметки, используя папку и формат даты в имени файла, настроенные в Obsidian, считываемые из .obsidian/daily-notes.json вашего хранилища:

  • Локальный режим читает файл прямо из вашего примонтированного хранилища — ничего настраивать не нужно.

  • Удалённый режим получает его через синхронизацию конфигурации хранилища Obsidian Sync. Сервер по умолчанию тянет его (настройка SYNC_CONFIGS в .env), но вам, скорее всего, потребуется включить сторону отправки: Настройки Obsidian → Синхронизация → Синхронизация конфигурации хранилища, на каждом устройстве. Подробности: раздел «Ежедневные заметки» в удалённом руководстве.

Когда файл недоступен — или вы используете плагин Periodic Notes, настройки которого он не отражает — задайте DAILY_NOTES_FOLDER (любой путь относительно хранилища: Journal, Planner/Daily) и DAILY_NOTES_FORMAT (те же токены, что и в настройке формата даты Obsidian: YYYY-MM-DD-dddd, YYYY/MM/DD, MMM D, YYYY, …). Можно задать одно или оба — заданное значение всегда имеет приоритет над файлом конфигурации. Без обоих источников сервер возвращается к Daily Notes и YYYY-MM-DD.

Примечание: Некоторые токены формата даты не поддерживаются — порядковые (Do, Mo, DDDo, wo), dd (двухбуквенный день недели), d (номер дня недели), e, k/kk и локализованные форматы (LLLLL, LT, LTS). Сервер не может воспроизвести имена файлов, которые Obsidian создаёт с этими токенами, поэтому он никогда не смог бы найти заметки. Если ваш формат использует любой из них, vault_get_daily_note возвращает понятную ошибку — измените формат в Obsidian или задайте DAILY_NOTES_FORMAT с поддерживаемой альтернативой.


Целостность данных

Vault Cortex записывает в личные заметки — слой безопасности файлов создан для предотвращения повреждений, а не только ошибок.

  • Атомарные записи — каждая запись файла сначала помещается во временный файл, затем переименовывается. Читатели никогда не видят частичную или нулевую заметку. Эксклюзивное создание использует link() (POSIX без перезаписи), чтобы закрыть окно TOCTOU при перемещении заметок.

  • Мьютекс на файл — параллельные вызовы инструментов MCP сериализуются или быстро завершаются с ошибкой для каждого файла. Перемещения блокируют исходный файл, назначение и каждый источник обратных ссылок как единое целое.

  • Блокировка обхода путейresolveSafePath() разрешает путь, а затем проверяет префикс для каждого пути. Удаление защищённых путей отклоняется после нормализации. Имена файлов памяти отклоняют разделители на границе.

  • Скрытые пути недоступны — файлы и папки, начинающиеся с точки (.obsidian/, .trash/), никогда не появляются в списках или поиске, и любой вызов инструмента, направленный непосредственно на них, отклоняется, как в Obsidian. Конфигурации плагинов и их ключи API остаются вне досягаемости.

  • Предотвращение инъекций — поисковые запросы параметризованы и очищены для FTS5; содержимое подсказок обёрнуто в XML-маркеры данных с экранированием закрывающих тегов для предотвращения инъекций через разрыв тегов.

  • Укрепление контейнера — непривилегированный пользователь, init-процесс PID 1, отсутствие менеджеров пакетов в образе выполнения, базовый образ с закреплённым дайджестом, корректное завершение работы.

См. ARCHITECTURE.md → Целостность данных для деталей механизмов и SECURITY.md → Укрепление выполнения для того, как каждая часть сервера укреплена.


Аутентификация

Для сервера с доступом на чтение и запись к личным заметкам аутентификация не является опциональной. Vault Cortex реализует полную спецификацию OAuth 2.1, включая PKCE и ротацию refresh-токенов. Развёртывание AWS (SST) добавляет защиту в глубину: запросы проверяются на двух независимых уровнях (Lambda-авторизатор API Gateway + промежуточное ПО Express). Согласно анализу безопасности MCP BlueRock 2026, только 8,5% MCP-серверов реализуют OAuth; 41% не имеют аутентификации вообще.

Два метода:

Метод

Используется

Формат токена

OAuth 2.1

Claude Desktop, Claude Code, claude.ai, любой OAuth-клиент

JWT (HS256, 24 часа)

Статический bearer

Claude Code, MCP Inspector, curl

Сырой MCP_AUTH_TOKEN

OAuth использует динамическую регистрацию клиентов — не нужны Client ID/Secret. В браузере открывается страница согласия; введите ваш MCP_AUTH_TOKEN для одобрения. Refresh-токены имеют скользящий срок действия 60 дней (ежедневные пользователи никогда не проходят аутентификацию повторно). Ротация MCP_AUTH_TOKEN завершает все сеансы — каждый клиент повторно авторизуется через страницу согласия.

См. ARCHITECTURE.md → Аутентификация для полной схемы потока.


Варианты развёртывания

Локальный запуск на вашей машине. Удалённые развёртывания работают на VPS или хостинговой платформе контейнеров — ваше хранилище доступно, даже когда ноутбук закрыт.

Какой бы путь вы ни выбрали, сервер заменяем, а ваше хранилище — нет. Ваши заметки — это обычные Markdown-файлы, синхронизируемые Obsidian на все ваши устройства; контейнер хранит копию и индекс, который можно перестроить с нуля. Выключите VPS, удалите сервис Render или Railway, смените хостинг — те же файлы остаются на вашей машине и в Obsidian Sync, читаемые чем угодно. В этом отличие от ИИ-блокнота, чей настоящий дом — база данных вендора: здесь хост — это удобство, а не хранитель.

Путь

Что

Руководство

Локальный

Ваше хранилище на вашей машине — бесплатно, без облака

deploy/local/

Удалённый · в один клик

Render или Railway — один постоянный том, без управления сервером

deploy/render/ · deploy/railway/

Удалённый · самостоятельный

VPS + Obsidian Sync — доступ с любого устройства

deploy/remote/

Удалённый · AWS (SST)

Эталонное развёртывание IaC — автоматизированная инфраструктура, аутентификация с защитой в глубину

DEPLOY.md

Путь AWS включает CI/CD-конвейеры, созданные для этого репозитория — форкерам необходимо настроить свои собственные учётные данные и этап перед развёртыванием.

Каждый путь использует один и тот же образ, ghcr.io/aliasunder/vault-cortex:latest — это только MCP-сервер (локальный), :remote включает Obsidian Sync в том же контейнере под управлением s6-overlay (в один клик, самостоятельный и AWS). Один контейнер означает, что работает любой OCI-рантайм: docker run, Podman, nerdctl — Docker Compose необязателен.

Также на Docker Hub: те же образы зеркалируются на aliasunder/vault-cortex. GHCR — основной источник; теги Hub идентичны.

Стоимость: Удалённая настройка требует VPS или тариф хостинговой платформы, плюс $4 USD/мес за Obsidian Sync. Экземпляр на 2 ГиБ справляется с семантическим поиском для типичного хранилища; 4 ГиБ добавляют запас для параллельного поиска и больших хранилищ. Отказ от семантического поиска позволяет уменьшить требования. Локальный режим бесплатен. Эталонное развёртывание AWS обходится примерно в ~$17–29 USD/мес всё включено.

Развёртывание в один клик

Кнопки и предварительные требования находятся в Кратком руководстве → Удалённый доступ. Каждое руководство описывает развёртывание, где найти URL и токен, как обновлять и как удалять: deploy/render/ (из Blueprint render.yaml в корне репозитория) · deploy/railway/ (из опубликованного шаблона).

Сообщественные развёртывания

Шаблоны развёртывания, созданные и поддерживаемые сообществом — не тестировались здесь и могут отставать от релизов.

  • vault-cortex-aca — шаблон Bicep для Azure Container Apps от @flytzen. Запускает образ :remote за входом Container Apps с бесплатным управляемым HTTPS; хранилище намеренно эфемерно, с Obsidian Sync как источником истины.

Создали развёртывание для другой платформы? Откройте PR, чтобы добавить его сюда.


Разработка

# Run locally with hot reload
PUBLIC_URL=http://localhost:8000 MCP_AUTH_TOKEN=local-dev-token VAULT_PATH=~/Vault npm run dev:mcp

# Tests
npm test

# Full check suite
npm run prettier:check && npm run lint && npm test && npm run build

npm test включает интеграционные тесты, которые запускают реальный сервер и вызывают каждый инструмент и подсказку по HTTP — проверяя принудительную аутентификацию, поверхности инструментов, управляемые конфигурацией, целостность мутаций записи (каждая запись считывается обратно) и отклонение запуска при неправильной конфигурации. См. SECURITY.md → Тестирование и проверка для покрытия, связанного с безопасностью.

MCP Inspector — интерактивный браузерный интерфейс для тестирования инструментов:

# Start server (terminal 1), then:
npx @modelcontextprotocol/inspector
# Enter http://localhost:8000/mcp as URL, local-dev-token as Bearer token

См. CONTRIBUTING.md для полной настройки разработки.


Компаньон: навык obsidian-vault

MCP-сервер работает самостоятельно с любым клиентом. Для агентов, поддерживающих навыки (Claude Code, Cursor, Windsurf, Cline и 70+ других), навык obsidian-vault добавляет более глубокие знания об Obsidian-специфичном Markdown — соглашения о frontmatter, синтаксис callout и форматы, специфичные для плагинов, такие как Dataview, Tasks и Kanban.

npx skills add aliasunder/agent-skills --skill obsidian-vault

Исходный код навыка →


Дорожная карта

Фаза

Что

Статус

1

CRUD хранилища, полнотекстовый поиск (FTS5), слой памяти, OAuth 2.1

Завершено

2a

Гибридный поиск — FTS5 + вектор + слияние RRF, чанкинг с учётом заголовков

Завершено

2b

Реранкер — кросс-энкодерное реранжирование, смешивание оценок с учётом позиции

Завершено

3a

Слой задач — индекс задач по всему хранилищу, структурированные запросы и обновление задач одним вызовом (форматы эмодзи Tasks + Dataview)

Завершено

3b

Воспоминания памяти — извлечение на уровне записей из датированной истории слоя памяти

Завершено

3c

Графовые запросы — многошаговый обход существующего графа вики-ссылок хранилища (пути, окрестности)

Исследуется


Благодарности

Синхронизация Obsidian работает на базе obsidian-headless — подхода к контейнеризации, вдохновлённого obsidian-headless-sync-docker от @Belphemur. Каркас супервизора s6-overlay для образа :remote был заимствован из поддерживаемого форка этого проекта и теперь находится в этом репозитории.

Гибридный конвейер поиска опирается на паттерны из qmd от @tobi — RRF-фьюжн с ранговыми бонусами, позиционно-зависимое смешивание оценок для реранжирования cross-encoder, гейтинг по хэшу содержимого и чанкинг с учётом заголовков.

Вклад в проект

Инструкции по настройке окружения для разработки, соглашения о коде и правила оформления PR см. в CONTRIBUTING.md.

Лицензия

MIT

Образ :remote включает obsidian-headless (CLI ob), который является проприетарным — его package.json объявляет "license": "UNLICENSED" (© Dynalist Inc. / Obsidian). Он устанавливается из публичного npm при сборке; лицензия MIT здесь не распространяется на него, и его использование требует активной подписки Obsidian Sync. Образ :latest (локальный) не содержит проприетарных компонентов.

Безопасность

Сообщайте об уязвимостях конфиденциально — см. SECURITY.md.

Available Tools

33 tools
vault_create_taskCreate TaskA

Create a correctly-formatted task in one call — description, target heading, dates, priority, block_id, and optional checklist sub-items. The task is always created as [ ] (todo) with ➕ today auto-stamped — starting work is vault_update_task's job. Metadata is written in the format the vault's Tasks plugin is configured for (emoji unless the plugin config says Dataview).

Example: vault_create_task({ path: "TASKS.md", description: "Fix login bug", block_id: "fix-login", heading: "Active", priority: "high", due: "2026-09-15" }) Example: vault_create_task({ path: "TASKS.md", description: "Ship the feature", block_id: "ship-feature", heading: "Up Next", subtasks: ["Design", "Implement", "Test"] }) — card with checklist stages Example: vault_create_task({ path: "TASKS.md", description: "Sub-bug", block_id: "sub-bug", parent_block_id: "fix-login", due: "2026-09-01" }) — full sub-task under a parent identified by block_id Example: vault_create_task({ path: "TASKS.md", description: "Quick fix", block_id: "quick-fix", parent_line: 42 }) — sub-task under a parent identified by line number Example: vault_create_task({ path: "TASKS.md", description: "Urgent fix", block_id: "urgent-fix", heading: "Active", position: "top" }) — insert at the top of a lane instead of the default bottom

When to use: Creating a new task card on a board or in a note. Guarantees correct field ordering (description → priority → ➕ created → 🛫 start → ⏳ scheduled → 📅 due → 🆔 task_id → ⛔ depends_on → ^block_id) so the card round-trips through vault_list_tasks with all fields intact. For lightweight checklist items under an existing card (no metadata), use vault_update_task's add_subtasks param instead.

Parameters:

  • path (required): vault-relative path to the note (must end in ".md"). The note must already exist.

  • description (required): the task text (before metadata fields).

  • block_id (required): the ^block-id for stable identification — letters, digits, and hyphens only. Must be unique within the note.

  • heading: target heading. Required on Kanban boards (notes with kanban-plugin frontmatter); optional on regular notes (omit to append at end of body).

  • parent_block_id / parent_line: the existing task to nest under as a sub-task, identified by its ^block-id or its 1-based line number — the same pair vault_update_task uses (block_id / line). Pass at most one. Either is mutually exclusive with heading — a sub-task lives wherever its parent lives.

  • position: "top" or "bottom" — where within the heading section the task is placed. Defaults to "bottom" (append). Kanban boards with new-card-insertion-method set to "prepend" default to "top" instead. Ignored when no heading or when placing under a parent.

  • priority: "highest" | "high" | "medium" | "low" | "lowest". Omit for normal priority (the plugin ranks "no signifier" between medium and low).

  • due / scheduled / start: YYYY-MM-DD dates (calendar-validated). Omit a date rather than guessing — an absent 📅 means "no deadline".

  • task_id: Tasks plugin 🆔 identifier for dependency chains.

  • depends_on: non-empty string array of Tasks plugin ⛔ dependency IDs (🆔 values of other tasks).

  • subtasks: string array of checklist item descriptions — created as indented [ ] lines under the card (no metadata, no block_ids). For full sub-tasks with their own dates, priority, and block_id, make a separate vault_create_task call with parent_block_id.

  • format: "emoji" or "dataview" — overrides the auto-detected Tasks plugin format (emoji when no plugin config is present).

Errors:

  • "note not found" — path does not exist

  • "heading required for Kanban boards" — kanban-plugin note without heading

  • "heading "X" not found; available: ..." — no heading matches; the error lists the note's headings

  • "parent task not found" — parent_block_id or parent_line doesn't resolve to a task (message names the blockId or line tried)

  • "parentBlockId and parentLine are mutually exclusive" — both parent_block_id and parent_line were passed; drop one

  • "parent and heading are mutually exclusive" — a parent (parent_block_id or parent_line) and heading were both passed; drop one

  • "blockId ... already exists in this note" — pick a block_id not yet used in the note

  • "blockId ... contains invalid characters" — block_id must match [a-zA-Z0-9-]+

  • "description is empty" / "dependsOn cannot be empty" / "subtasks cannot contain an empty item" — whitespace-only description, an empty depends_on array, or a whitespace-only checklist item

  • "description must be a single line" / "subtasks items must be a single line" — a task is one file line; a line break in the text would split its metadata onto a line the parser never reads

  • "taskId ... contains invalid characters" / "dependsOn entry ... contains invalid characters" — task_id and every depends_on entry must match [a-zA-Z0-9_-]+ (the Tasks plugin's id grammar)

  • "invalid date" — a date param fails calendar validation

  • "concurrent write in progress" — another write to this note is in flight; retry

Returns: JSON { path, line, description, block_id, heading, subtasks, changes } — line is the new card's 1-based position; heading is the nearest heading above the new task (omitted when the note has none); subtasks lists each checklist item written as { line, description } (omitted when none) — checklist items carry no block_id, so line is the handle for a follow-up update; changes lists every field written as "field: before → after", with "(none)" for an absent value.

ParametersJSON Schema
NameRequiredDescriptionDefault
dueNoDeadline (📅), YYYY-MM-DD, calendar-validated. Omit when there is no deadline.
pathYesVault-relative path to the note (must end in ".md"). The note must already exist.
startNoEarliest day work can begin (🛫), YYYY-MM-DD, calendar-validated.
formatNoField format. Default: auto-detected from .obsidian/ config, falling back to emoji.
headingNoTarget heading. Required on Kanban boards; optional on regular notes (omit to append at end of body).
task_idNoTasks plugin 🆔 identifier other tasks can name in depends_on.
block_idYesThe ^block-id for stable identification — letters, digits, and hyphens only ([a-zA-Z0-9-]+). Must be unique within the note.
positionNoWhere within the heading section the task is placed. Defaults to bottom. Kanban boards with new-card-insertion-method set to prepend default to top instead. Ignored when no heading or when placing under a parent.
priorityNoPriority signifier (🔺⏫🔼🔽⏬). Omit for normal priority — no signifier is written.
subtasksNoChecklist item descriptions — created as indented [ ] lines under the card (no metadata). For full sub-tasks with dates, priority, and block_id, make a separate call with parent_block_id.
scheduledNoDay the work is planned for (⏳), YYYY-MM-DD, calendar-validated.
depends_onNoTasks plugin ⛔ dependency IDs (🆔 values of other tasks). Non-empty; omit when there are no dependencies.
descriptionYesThe task text (before metadata fields).
parent_lineNo1-based line number of an existing task to nest under as a sub-task. Mutually exclusive with parent_block_id and heading. Fragile if the file changed since the line was read.
parent_block_idNo^block-id (without the ^) of an existing task to nest under as a sub-task. Mutually exclusive with parent_line and heading.

TDQS

A5/5.0
Behavior5/5

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

The description goes well beyond the sparse annotations (readOnlyHint=false, destructiveHint=false) by disclosing the exact write behavior: the task is always created as [ ] (todo) with ➕ auto-stamped, metadata ordering, format auto-detection, and a comprehensive list of error conditions. It even explains the return value shape. Nothing contradicts the annotations; it adds rich behavioral context that the annotations only hint at.

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

Conciseness5/5

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

The structure is exemplary: a clear opening purpose, five illustrative examples, a succinct 'When to use' section, a well-organized parameter list (every parameter described with purpose and constraints), followed by an error catalog and return format. Despite length (necessary for a 15-parameter tool), every sentence earns its place — no filler, no repetition. The content is front-loaded with the most decision-relevant information.

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?

For a tool with 15 parameters, 3 required, and no output schema, the description is remarkably complete. It covers return values (JSON shape), error conditions (every plausible failure), formatting conventions, and edge cases like concurrent writes and parent/task relationships. An agent has everything needed to call the tool correctly, including examples that demonstrate the full range of usage. Nothing essential is missing.

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% — each parameter already has a description. However, the description adds substantial meaning beyond the schema: the field-ordering guarantee, the relationship between parent_block_id/parent_line and heading, the position default nuance ('Kanban boards with new-card-insertion-method set to prepend default to top instead'), and the subtasks vs. full sub-task distinction. This is far above the baseline 3 and earns a 5.

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 description states a specific verb ('Create a correctly-formatted task in one call'), the resource (a task card in a note), and enumerates the key fields. It differentiates from vault_update_task by noting the task is always created as [ ] (todo) and that starting work is vault_update_task's job. Examples concretely illustrate the purpose.

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?

It explicitly states when to use: 'When to use: Creating a new task card on a board or in a note.' It also gives a clear exclusion and alternative: 'For lightweight checklist items under an existing card (no metadata), use vault_update_task's add_subtasks param instead.' This is exactly the kind of when/when-not guidance that the dimension asks for.

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

vault_delete_memoryDelete Memory EntryA
Destructive

Delete a single dated entry from a About Me/ memory file. Both date and entry text are required for exact matching — ensures only the intended entry is removed.

Example: vault_delete_memory({ file: "Opinions", section: "AI tooling & memory (newest first)", date: "2026-05-01", entry: "Prefer X over Y" })

When to use: Removing an entry that was wrong when it was written — a mistake, a misattribution, or something never true. Memory files are append-only by default, so do NOT delete to reflect a change: when a preference or fact has since evolved, append the new state via vault_update_memory (newest-first naturally supersedes). The exception is a file whose frontmatter declares entry-policy: living (check via vault_list_memory_files) — a current-state file where deleting an expired entry is the intended maintenance. Call vault_get_memory(file, section) first to see exact entry text for matching. Prefer vault_update_memory to supersede a changed entry; prefer vault_delete_note for deleting entire non-protected notes.

Parameters:

  • date + entry together uniquely identify the bullet line within the given section. If multiple entries share the same date and text, deletion fails as ambiguous.

  • section scopes the match — an identical entry under a different heading is not found. Section matching is case-insensitive, with or without the "(newest first)" suffix.

Errors:

  • "memory file must not start with a dot" — a dot-prefixed name would target a hidden file; memory files are always visible notes.

  • "date must be a real ISO calendar date" — date only accepts an existing calendar date in bare YYYY-MM-DD form. A hand-edited bullet carrying an impossible date cannot be targeted by this tool — remove it with vault_delete_span or a manual edit.

  • "section not found: …" — no H2 heading matches; the error lists the file's available sections

  • "no entry matching …" — no bullet matched the given date and entry text; verify exact text via vault_get_memory(file, section).

  • "ambiguous: N entries match …" — more than one identical bullet exists in the section (e.g. from hand edits, sync conflicts, or entries predating duplicate protection; vault_update_memory refuses to write exact duplicates). Remove the extra copy with vault_delete_span (pass first_match: true — identical lines make every anchor ambiguous) or a manual edit, then retry.

  • "refusing memory write: … would shrink content" — safety guard blocked a write that would remove more than half the file. Re-read with vault_get_memory to confirm current content before retrying.

Returns: Confirmation message.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateYesISO YYYY-MM-DD date of the entry (e.g. "2026-05-01"). Must match the date shown by vault_get_memory.
fileYesMemory file name without .md (e.g. "Principles")
entryYesExact entry text as shown by vault_get_memory — without the "- **YYYY-MM-DD**: " prefix or bullet. Both date and entry must match for deletion.
sectionYesH2 section heading containing the entry. Matched case-insensitively, with or without the "(newest first)" suffix.

TDQS

A4.9/5.0
Behavior5/5

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

The description fully informs the agent about behavioral traits beyond annotations. It discloses the exact matching requirement, case-insensitive section matching, common errors (ambiguous, no entry, dot-prefix error), the safety guard that blocks writes shrinking content by more than half, and return value. The annotation shows destructiveHint: true, and the description aligns with this by detailing deletion behavior and blockers.

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 thorough and front-loaded with the core purpose, but it is somewhat lengthy. Every sentence adds value, but the error details could be slightly compressed. Still, it is well-structured with clear paragraphs for when to use, parameters, and errors.

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 the tool's complexity (4 required parameters, sibling tools for deletion and update), the description is remarkably complete. It covers usage boundaries, error cases, safety blocks, and return values. No output schema exists, but the return is simple ('Confirmation message') and the errors are enumerated, making the agent well-equipped to handle the tool.

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?

The description adds significant meaning beyond the schema. It explains how 'date + entry together uniquely identify the bullet line', notes that identical entries cause ambiguity, details section matching behavior (case-insensitive, ignoring suffix), and provides a full example. Schema coverage is 100% but the description enriches every parameter with context on errors and usage.

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 description clearly states 'Delete a single dated entry from an About Me/ memory file'. It identifies the specific verb (delete) and resource (dated entry from a memory file), and distinguishes this from sibling tools like vault_delete_span, vault_delete_note, and vault_update_memory by specifying exact matching and alternative use cases.

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?

The description provides extensive guidance on when to use and when not to use this tool. It explicitly says 'do NOT delete to reflect a change', advises preferring vault_update_memory for superseding changed entries, and mentions exceptions for 'living' files. It also recommends calling vault_get_memory first and lists alternatives like vault_delete_span for ambiguous cases.

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

vault_delete_noteDelete NoteA
Destructive

Permanently delete a markdown note — removed from disk directly (no trash, no undo). After deletion, links to it from other notes become broken (detectable via vault_get_backlinks). Protected paths (About Me/ and the daily notes folder (read from DAILY_NOTES_FOLDER or .obsidian/daily-notes.json, defaulting to Daily Notes/)) are refused.

Example: vault_delete_note({ path: "Scratch/temp.md" }) Example: vault_delete_note({ path: "Archive/2024/old.md", prune_empty_folders: true }) — also remove "Archive/2024" (and "Archive") if deleting the note empties them.

When to use: Removing a note you no longer need. Prefer vault_delete_memory for removing individual dated entries from About Me/ memory files.

Behavior: With prune_empty_folders, pruning is best-effort and runs after the delete — it never fails the call, so the note is always removed even if a folder can't be removed.

Errors:

  • "cannot delete protected path" — the path sits under a protected folder; use vault_delete_memory for memory entries

  • "path traversal blocked" — path escapes the vault 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 deletable, matching Obsidian

  • "concurrent write in progress" — another write to this note is in flight; retry

  • "note not found: …" — the note does not exist; verify the path with vault_list_notes before deleting

Returns: Confirmation message, noting how many empty folders were pruned when any were.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesVault-relative path of the note to delete, including the ".md" extension
prune_empty_foldersNoWhen true, remove the note's parent folder(s) if deleting it leaves them empty, walking up to (but never including) the vault root. Default false matches Obsidian, which leaves empty folders in place. Only removes a folder with zero entries — a folder still holding any file, including a hidden one like .DS_Store, is left alone.

TDQS

A4.9/5.0
Behavior5/5

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

While annotations already declare destructiveHint=true, the description adds substantial behavioral context: no trash/undo, link breakage detectable via vault_get_backlinks, protected path refusal, best-effort folder pruning that never fails the delete, concurrent write errors, and hidden path blocking. This far exceeds what annotations alone convey.

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

Conciseness5/5

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

The description is long but tightly structured and front-loaded: key destructive behavior first, then examples, usage guidance, error handling, and return value. Every section earns its place, especially for a destructive tool where edge cases and failure modes are critical for safe invocation.

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?

The description covers invocation, examples, protected paths, error conditions with remedies, pruning semantics, and the return value. Given the destructive nature and lack of an output schema, this is a complete and well-rounded definition that leaves little ambiguity for an agent.

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

Parameters4/5

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

Schema coverage is 100% with strong descriptions for both parameters, so the baseline is 3. The description adds value beyond the schema through concrete invocation examples and clarifies that prune_empty_folders is best-effort and never causes the deletion to fail. This is useful extra meaning, though not dramatically more than the schema already provides.

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 description opens with a specific verb and resource: 'Permanently delete a markdown note', and immediately clarifies the destructive scope (removed from disk, no trash, no undo). It also distinguishes itself from vault_delete_memory by noting that memory entries should go through that sibling tool instead.

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?

The 'When to use' section explicitly states the intended use case and names the preferred sibling alternative (vault_delete_memory) for memory entries. The errors section also routes remediation, such as using vault_delete_memory for protected About Me paths and vault_list_notes to verify paths before deleting.

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

vault_delete_spanDelete SpanA
Destructive

Delete a contiguous block of whole lines from a note's body by referencing short anchor substrings instead of reproducing the full block text. Each anchor locates a full line — the entire line is selected, not just the matching substring. Case-sensitive matching. Properties are preserved; YAML formatting may be normalized to block style on first edit. Operates on the body only.

Example: vault_delete_span({ path: "Tracker.md", start_anchor: "| 2024-03-02 | Acme" }) — deletes the one table row whose line contains that fragment. Example: vault_delete_span({ path: "Notes/Plan.md", start_anchor: "> [!warning] Stale", end_anchor: "remove after launch" }) — deletes from the start anchor line through the end anchor line.

When to use: Removing a block you have already read — a table row, callout, or run of list items — where reproducing it exactly as old_text would be error-prone. Pick a short, unique fragment of the first line for start_anchor and, for a multi-line block, the last line for end_anchor. Prefer vault_replace_in_note for small in-place edits (this tool only deletes). To replace a block, prefer vault_replace_span (one atomic step); otherwise delete it here, then vault_patch_note to add the new content.

Parameters:

  • start_anchor + end_anchor define a line range, not a text range — each anchor locates a full line, and entire lines are removed (never cuts mid-line). Omit end_anchor for a single-line delete.

  • end_anchor is searched at or after the start line, so the span can never run backward. If both match the same line, only that one line is deleted.

  • first_match applies to both anchors independently — when an anchor matches multiple lines, takes the first instead of erroring.

  • Blank-line runs left by the deletion are collapsed to a single blank line.

Errors:

  • "note not found" — verify path with vault_list_notes

  • "anchor not found" — fragment not on any line; verify with vault_read_note

  • "ambiguous start anchor …" / "ambiguous end anchor …" — the anchor matches multiple lines; use a longer fragment or set first_match: true

  • "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

Returns: Confirmation with lines removed and a truncated preview of the deleted text.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesVault-relative path to the note, including the ".md" extension (e.g. "Tracker.md", "Notes/Plan.md")
end_anchorNoShort, unique substring that identifies the LAST line of the block, searched at or after the start_anchor line. The entire line is selected. Omit to delete just the single line containing start_anchor.
first_matchNoIf an anchor matches more than one line, delete using the first match instead of erroring (default: false — ambiguity is an error).
start_anchorYesShort, unique substring that identifies the first line of the block (case-sensitive). The entire line is selected, not just the substring. Pick a brief fragment — do not paste the whole block.

TDQS

A5/5.0
Behavior5/5

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

Beyond the destructiveHint annotation, the description discloses line-level selection (never mid-line), case-sensitive matching, end_anchor search order preventing backward spans, first_match behavior, blank-line collapse, property preservation with possible YAML normalization, and specific error modes with recovery steps. This is rich behavioral context for a destructive operation.

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

Conciseness5/5

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

The description is long but every section earns its place: primary behavior, examples, usage guidance, parameter semantics, error handling, and return value. Information is front-loaded and organized with clear labels and bullets, avoiding rambling prose.

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?

For a destructive, nuance-heavy tool, the description covers prerequisites (read the block first), anchor selection guidance, edge cases including ambiguous anchors and concurrent writes, hidden path restrictions, and return value. There is no output schema, so the explicit return description closes the last gap.

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?

Though schema coverage is 100%, the description adds crucial semantics not present in the schema: anchors select whole lines, end_anchor must be at or after the start line, omitting end_anchor means single-line deletion, and first_match applies independently to each anchor. The two worked examples demonstrate valid start/end anchor choices.

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 description opens with a specific verb and resource: 'Delete a contiguous block of whole lines from a note's body' via anchor substrings. It clearly differentiates this from write/replace siblings by emphasizing that it only deletes and operates on the body only.

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 describing the ideal case (removing an already-read block where reproducing old_text is error-prone) and naming alternatives: prefer vault_replace_in_note for small edits and vault_replace_span for block replacement, with a fallback workflow. This makes the selection decision unambiguous.

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

vault_find_orphansFind OrphansA
Read-onlyIdempotent

Find notes with no incoming links from other notes — orphans are disconnected from the knowledge graph and may be forgotten or need linking. A note that only links to itself still counts as an orphan (self-links are ignored).

Example: vault_find_orphans({ exclude_folders: ["Daily Notes","Templates","About Me"] })

When to use: Vault maintenance — surfacing notes to integrate into the graph. Link an orphan by mentioning it from a relevant note with vault_patch_note. Prefer vault_get_backlinks to check the connectivity of one specific note rather than scanning the whole vault.

Parameters:

  • exclude_folders replaces the defaults (["Daily Notes","Templates","About Me"]), it does not add to them — include the defaults yourself to keep them. Matched by folder prefix, recursing into subfolders ("Projects" also excludes "Projects/Archive").

  • limit (default 50) caps results after sorting by most-recently-modified.

Errors:

  • An empty array means no orphans were found (after exclusions), not an error.

Returns: JSON array of note metadata (path, title, tags, related, folder, type, created, modified, bytes, leading_callout?, additional_properties), sorted by most recently modified. bytes is the on-disk file size.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax results (default 50)
exclude_foldersNoFolders to exclude — replaces the defaults (["Daily Notes","Templates","About Me"]), not merged

TDQS

A5/5.0
Behavior5/5

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

Annotations already indicate read-only, non-destructive, idempotent behavior. The description adds nuance: self-links ignored, exclude_folders replaces defaults with prefix matching, sorting by most recently modified, and empty array means no orphans (not error). No contradictions.

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

Conciseness5/5

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

Well-structured with clear sections (purpose, example, usage, parameters, errors, returns). Every sentence adds value without redundancy or filler.

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 no output schema, the description fully covers return format (JSON array of note metadata sorted by modified), error cases (empty array), and parameter behavior, leaving no ambiguity for the agent.

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?

Despite 100% schema coverage, the description adds crucial details: exclude_folders replaces defaults (not merges), includes prefix recursion behavior, and reminds to include defaults. For limit, clarifies default and sorting impact.

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 description clearly states the tool finds notes with no incoming links, using the specific term 'orphans'. It differentiates from sibling `vault_get_backlinks` by explicitly noting the alternative for single-note connectivity checks.

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?

Provides explicit 'when to use' (vault maintenance) and alternative (`vault_get_backlinks` for specific notes). Includes a concrete example of usage with parameters.

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

vault_get_daily_noteGet Daily NoteA
Read-onlyIdempotent

Read a daily note by date, using the vault's configured Daily Notes folder and filename date format. Each setting comes from the DAILY_NOTES_FOLDER / DAILY_NOTES_FORMAT env vars, falling back to the vault's .obsidian/daily-notes.json, then to "Daily Notes" and YYYY-MM-DD. Defaults to today if no date is provided.

Example: vault_get_daily_note({ date: "2026-05-13" }) Example: vault_get_daily_note({}) — returns today's daily note

When to use: When you need today's or a specific date's daily note. Handles path resolution automatically using the vault's Obsidian config — you don't need to know the folder name or filename format. To append content to a daily note section, use the returned path with vault_patch_note. Use vault_recent_notes to review recent vault activity around a date (not date-filtered — returns globally recent notes).

Parameters:

  • date is ISO YYYY-MM-DD (e.g. "2026-05-13"). Defaults to today in the server's local timezone. Past and future dates are both valid — the tool resolves the configured path for any date and reports exists: false if the note hasn't been created yet. The path is derived from the server's daily-notes settings, so callers never need to construct daily note paths manually.

Errors:

  • "invalid date" — use YYYY-MM-DD format (e.g. "2026-05-13", not "May 13")

  • "daily note format contains unsupported token(s): ..." — the configured format uses tokens the server cannot reproduce (ordinals like Do/Mo, dd, d, e, k/kk, or the L-family localized formats); change the format in Obsidian or set DAILY_NOTES_FORMAT to a supported alternative

Returns: JSON with path (string — resolved vault-relative path), content (string|null — full note body, or null when the note doesn't exist), and exists (boolean). When exists is false, create the note with vault_write_note using the returned path.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateNoYYYY-MM-DD (e.g. "2026-05-13", "2025-12-31"). Defaults to today in the server's timezone. Invalid formats like "May 13" return an error.

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already declare readOnly, idempotent, and non-destructive. The description adds behavioral details beyond annotations: returns exists:false if note missing, resolves path automatically, explains timezone handling, and lists error conditions. No contradictions.

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 well-structured with clear sections, but contains redundancy: the error text and 'exists: false' behavior are repeated. Could be tightened without losing clarity, but is still acceptable.

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?

No output schema exists, yet the description fully explains the return JSON structure (path, content, exists), default behavior, error cases, and interaction with other tools. It is complete for the tool's function.

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% but the description enriches the date parameter by explaining default to today, server timezone usage, invalid format error, and that the path is derived automatically. This adds meaning beyond the schema.

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 description clearly states 'Read a daily note by date' with a specific verb and resource, and distinguishes itself from siblings like vault_read_note by specifying it uses the daily notes folder and format. It is unambiguous and specific.

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?

Explicitly states when to use ('When you need today's or a specific date's daily note') and contrasts with vault_recent_notes ('not date-filtered'). Also suggests using vault_patch_note for appending, providing clear guidance on alternatives.

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

vault_get_memoryGet MemoryA
Read-onlyIdempotent

Read semantic memory from About Me/ files. These are structured memory files containing dated bullet entries organized under H2 headings. With file: single file content. With file+section: just that H2 section's entries. No args: all files concatenated (frontmatter stripped) — can be large. Returns empty string when no memory files exist yet.

Example: vault_get_memory({ file: "Principles", section: "Decision heuristics (newest first)" })

When to use: Reading user preferences, principles, opinions, or other persistent context stored in About Me/ files. Call vault_list_memory_files first to discover valid file and section names. Prefer vault_read_note for reading non-memory notes.

Errors:

  • "section requires a file" — section was provided without file; pass both or just file

  • "memory file not found" — file does not exist in About Me/; call vault_list_memory_files to discover valid names

  • "memory file must not start with a dot" — a dot-prefixed name would be a hidden file; memory files are always visible notes

  • "section not found: …" — no H2 heading matches; the error lists the file's available sections

Returns: Raw markdown text.

ParametersJSON Schema
NameRequiredDescriptionDefault
fileNoMemory file name without .md (e.g. "Principles", "Opinions")
sectionNoH2 section heading (e.g. "Decision heuristics (newest first)"). Matched case-insensitively, with or without the "(newest first)" suffix. Call vault_list_memory_files first to discover valid names.

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is clear. The description adds behavioral context beyond annotations: it notes that returning no args yields all files concatenated ('can be large'), returns empty string when no memory files exist, and details each error case. The only gap is not explaining the exact return format (raw markdown is mentioned) or pagination, but that's minor given the tool's simplicity.

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 well-structured with clear sections: mode behavior, example, when to use, error list, return type. Every sentence provides useful information. Minor inefficiency: repeating 'call vault_list_memory_files first' in both the guidelines and the schema description could be consolidated, but overall it's concise.

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

Completeness4/5

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

The description is complete for a read-only tool with two optional parameters. It covers all input modes, error cases, appropriate prerequisites (list files first), and return type. With no output schema, the description adequately explains return values (raw markdown, empty string). The only minor gap is not explaining how large concatenated output might be limited or truncated, but that's acceptable for this use case.

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

Parameters4/5

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

Schema coverage is 100%, so the baseline is 3. The description adds significant value by explaining how the parameter combos affect output (file, file+section, no args) and giving a concrete example. It also clarifies the section matching behavior (case-insensitive, optional suffix). However, it doesn't explain the exact format of the section heading beyond saying 'H2 heading', which is already clear from the example.

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 description clearly states that the tool reads semantic memory from 'About Me/' files and describes three modes of operation (file, file+section, no args). It distinguishes itself from sibling tools like vault_read_note, vault_memory_recall, and vault_get_daily_note by focusing specifically on structured memory files with bullet entries.

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?

The description explicitly tells the agent when to use this tool (reading user preferences, principles, opinions) and when not to ('Prefer vault_read_note for reading non-memory notes'). It also advises calling vault_list_memory_files first to discover valid file and section names, which is a valuable usage guideline.

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

vault_insert_at_anchorInsert at AnchorA

Insert content as whole lines before or after a specific line identified by a short anchor substring. Case-sensitive matching; an anchor matching more than one line is an error unless first_match is set. Same anchor resolution as vault_delete_span. Properties are preserved; YAML formatting may be normalized to block style on first edit. Operates on the body only.

Example: vault_insert_at_anchor({ path: "Tracker.md", anchor: "| 2024-03-02 | Acme", position: "after", content: "| 2024-03-03 | Beta Corp | New entry |" }) — inserts a new table row after the matched row. Example: vault_insert_at_anchor({ path: "Notes/Plan.md", anchor: "## Phase 2", position: "before", content: "> [!note] Phase 1 must close before this starts.\n" }) — inserts a callout and a blank line above the Phase 2 heading.

When to use: Adding content at a precise location identified by a nearby line's text, without needing to know the heading structure. Good for inserting rows into tables, adding items into lists at a specific position, or placing content relative to a known landmark line. Prefer vault_patch_note for heading-targeted inserts (append/prepend to a section). Prefer vault_replace_span when replacing a block rather than inserting next to it.

Parameters:

  • anchor locates a full line — the content is inserted as whole lines before or after it (never splits a line).

  • position: "before" inserts above the anchor line; "after" inserts below it.

  • content is inserted verbatim — blank lines inside it are kept, and a trailing newline adds a blank line after the inserted block.

  • first_match: when the anchor matches multiple lines, takes the first instead of erroring.

Errors:

  • "note not found" — verify path with vault_list_notes

  • "anchor not found" — fragment not on any line; verify with vault_read_note

  • "ambiguous anchor …" — the anchor matches multiple lines; use a longer fragment or set first_match: true

  • "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.

Returns: Confirmation message "Inserted lines <before|after> anchor in " — N counts the lines content supplied.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesVault-relative path to the note, including the ".md" extension (e.g. "Notes/Plan.md", "Tracker.md")
anchorYesShort, unique substring on the line to insert next to (case-sensitive). Pick a brief fragment — do not paste the whole line.
contentYesContent to insert (one or more lines), inserted verbatim as whole lines — blank lines are kept, and a trailing newline adds a blank line after the block.
positionYes"before" places the content on the lines above the anchor line; "after" places it on the lines below. The anchor line itself is never changed.
first_matchNoIf the anchor matches more than one line, use the first match instead of erroring (default: false — ambiguity is an error).

TDQS

A4.9/5.0
Behavior5/5

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

The description goes well beyond the annotations by disclosing key behavioral traits: case-sensitive matching, ambiguity errors unless first_match is set, whole-line insertion that never splits a line, verbatim content handling with trailing-newline effects, properties being preserved, YAML normalization to block style on first edit, and operation on the body only. It also enumerates specific error conditions such as 'concurrent write in progress' and 'hidden path blocked.' No contradiction with the annotations exists.

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 exceptionally well structured, with clear sections for behavior, examples, when-to-use, parameters, errors, Obsidian syntax, and return value. Every section contributes actionable information, and the core behavior is front-loaded. It loses one point for some redundancy with the schema's parameter descriptions and for being longer than strictly necessary, but the length is largely justified by the tool's complexity and the absence of an output schema.

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?

The description is fully self-contained for an agent to invoke the tool correctly: it defines matching semantics, insertion direction, error handling, return message format, hidden-path restrictions, concurrent-write behavior, and Obsidian Markdown escaping caveats. With no output schema, the explicit 'Returns' section fills the gap completely. The sibling routing and examples also make the tool's place in the broader API clear.

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?

Although schema coverage is 100%, the description adds meaningful behavioral semantics beyond the schema: the anchor is a 'short unique substring' that must be case-sensitive and can match multiple lines; content is inserted as whole lines and never splits the anchor line; first_match changes ambiguity handling from error to first-match. The clear examples further illustrate parameter usage by showing concrete path, anchor, position, and content values. This is more than the baseline 3 expected when schema coverage is high.

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 description opens with a specific verb and resource: 'Insert content as whole lines before or after a specific line identified by a short anchor substring.' It clearly differentiates from siblings by naming vault_patch_note and vault_replace_span as alternatives for different insert/replace scenarios, and even notes the shared anchor resolution with vault_delete_span. An agent can immediately tell what this tool does and how it differs from other vault mutation tools.

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?

The 'When to use' section is explicit about the intended scenarios: precise location by nearby line text, table row insertion, and list positioning. It also gives direct exclusions: 'Prefer vault_patch_note for heading-targeted inserts' and 'Prefer vault_replace_span when replacing a block rather than inserting next to it.' This gives an agent clear routing logic among sibling tools.

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

vault_list_filesList FilesA
Read-onlyIdempotent

List non-markdown files in the vault or a folder — images, canvases, PDFs, data files — with per-file byte sizes and per-extension counts.

Example: vault_list_files({}) — every non-markdown file in the vault Example: vault_list_files({ folder: "attachments" }) Example: vault_list_files({ extensions: [".png", ".jpg"], limit: 20 })

When to use: discovering what files exist before reading them with vault_read_file. vault_search, vault_list_notes, and vault_search_by_folder cover only markdown notes, so this is the discovery surface for everything else. For the files one specific note links to, prefer vault_get_outgoing_links.

Parameters:

  • folder: folder path filter (e.g. "attachments" or "Projects/media"), searched recursively; omit for the whole vault

  • extensions: restrict to these extensions — case-insensitive, with or without the leading dot (".png" and "png" both work)

  • limit: maximum entries returned (default 50). extension_counts and total always reflect the full filtered set, not just the returned page.

Errors:

  • A visible folder containing no files — or one that doesn't exist — returns an empty listing, not an error.

  • A folder path escaping the vault (e.g. "../elsewhere") is rejected with a path-traversal error.

  • "hidden path blocked" — the folder is hidden (dot-prefixed, like ".obsidian"); hidden folders are not listable, matching Obsidian.

Returns: JSON with files (array of { path, extension, bytes }, sorted by path), extension_counts (per-extension totals over the full filtered set), total (full filtered count), and truncated (true when total exceeds limit). bytes is the on-disk file size, not the delivery cost: reading an image via vault_read_file returns a copy shrunk to fit when needed, so a large listed image is still cheap to read. Text formats return verbatim, so their listed size is what a read delivers. Files of supported types are readable via vault_read_file; vault_search covers markdown notes.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax entries returned (default 50).
folderNoFolder path to search recursively (e.g. "attachments"). Omit to list the whole vault.
extensionsNoOnly include these extensions, case-insensitive, leading dot optional (e.g. [".png", "jpg"]).

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare readOnlyHint=true, destructiveHint=false, idempotentHint=true. The description goes well beyond: it explains that extension_counts/total reflect the full set even with truncation, describes path-traversal errors, hidden-folder blocking, and the difference between on-disk size vs delivery cost for images vs text, which annotations cannot convey.

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 well-structured with examples, usage guidance, parameter details, error cases, and return format—all clearly separated. It is slightly longer than strictly necessary (the bytes/large image detail could be condensed), but every section serves a distinct purpose.

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?

Despite having no output schema, the description fully documents the return format (files array, extension_counts, total, truncated). For a 3-parameter tool with zero required params, 100% schema coverage, and clear annotations, the description covers all behavioral and edge-case details an agent needs, including error conditions and cost considerations.

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

Parameters4/5

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

Schema coverage is 100%, so baseline is 3. The description adds significant value beyond the schema: explains case-insensitivity and leading-dot flexibility for extensions, clarifies default 50 for limit, and describes the recursive search behavior of folder. One deduction because it does not mention that bytes/large image behavior detail belongs more in the tool description than parameter semantics, but still adds substantial context.

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 description clearly states 'List non-markdown files in the vault or a folder' and explicitly contrasts with sibling tools like vault_search, vault_list_notes, and vault_search_by_folder that cover only markdown notes, making the scope unambiguous.

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?

The description provides explicit 'When to use' guidance, naming specific sibling tools (vault_search, vault_list_notes, vault_search_by_folder) and indicating when to prefer vault_get_outgoing_links instead, plus three clear examples showing common use cases.

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

vault_list_memory_filesList Memory FilesA
Read-onlyIdempotent

Discovery tool — lists About Me/ memory files with their H1/H2 heading structure, per-section entry counts, entry policy, and each file's leading callout (by convention a "Scope of this file" block describing what belongs in it). Does NOT return actual entries.

Example: vault_list_memory_files() returns file outlines with headings like "Decision heuristics (newest first)", entry counts, each file's entry policy, and its scope callout.

When to use: Discovering what memory files and sections exist — and what each file is for — BEFORE calling vault_get_memory, vault_update_memory, or vault_delete_memory. Always call this first to get valid file and section names, and to check a file's entry policy before pruning entries.

Errors:

  • An empty or nonexistent memory folder returns an empty array, not an error.

Returns: JSON array of file outlines, each { file, title, bytes, entry_policy, leading_callout, headings } — bytes is the on-disk file size; entry_policy is "append-only" (the default — entries are never edited or deleted) or "living" (a current-state file whose expired entries may be pruned; declared via entry-policy frontmatter); leading_callout is the file's top-of-file callout ({ type, title, body }), by convention a "Scope of this file" block, or null.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already indicate readOnlyHint=true and idempotentHint=true. The description adds value by detailing that an empty or nonexistent memory folder returns an empty array (not an error) and by explaining the return structure including the leading callout and entry_policy fields. No contradictions with 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 well-structured with a clear first sentence stating purpose, followed by an example, usage guidance, error behavior, and return format. It is appropriately detailed without being excessively verbose.

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 the tool has no parameters and no output schema, the description provides a complete picture: it explains what the tool returns (JSON array of file outlines with key fields), how to use it, and error handling. There are no gaps.

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

Parameters4/5

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

There are no parameters, so the baseline is 4 as per the guidelines. The description does not need to provide parameter information and correctly omits it.

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 description clearly states it's a discovery tool for listing memory files with their heading structure, entry counts, and entry policy. It explicitly distinguishes its purpose from sibling tools by noting it should be called before vault_get_memory, vault_update_memory, or vault_delete_memory.

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?

The description provides explicit guidance on when to use the tool: always before getting, updating, or deleting memory files to get valid file and section names and to check entry policy. This effectively differentiates its usage from sibling memory tools.

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

vault_list_notesList NotesA
Read-onlyIdempotent

List .md file paths in the vault, optionally filtered by folder and/or glob pattern. Returns paths only — not content or metadata.

Example: vault_list_notes({ folder: "Projects" }) Example: vault_list_notes({ glob: "**/session-log.md" })

When to use: Browsing what exists in a folder by filename, or finding notes matching a path pattern. Prefer vault_search_by_folder when you need metadata (tags, type, related) along with paths. Prefer vault_search for content-based discovery. Use vault_read_note to read a note from the results.

Parameters:

  • folder scopes the listing to a path prefix ("Projects" includes "Projects/Archive"). When combined with glob, the glob pattern is applied within the folder's scope.

  • glob supports * (any filename chars) and ** (any path depth). Applied to vault-relative paths.

Errors:

  • A nonexistent folder or no glob matches returns an empty array, not an error.

  • "hidden path blocked" — the folder is hidden (dot-prefixed, like ".obsidian"); hidden folders are not listable, matching Obsidian.

Returns: JSON array of vault-relative path strings (e.g. ["Projects/plan.md", "Notes/idea.md"]).

ParametersJSON Schema
NameRequiredDescriptionDefault
globNoGlob pattern for path filtering (e.g. "**/*session-log*.md"). Supports * and ** wildcards. Combined with folder when both are set.
folderNoFolder path prefix (e.g. "About Me", "Projects"). Includes all subfolders.

TDQS

A4.7/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the agent knows it's safe. The description adds crucial behavioral context: returns paths-only (not content), empty array for nonexistent folders, and hidden folder blocking ('hidden path blocked' error). This goes beyond annotations.

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

Conciseness5/5

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

The description is well-structured: purpose upfront, then usage guidelines, then sibling differentiation, then parameter details, then error cases, then return format. Every sentence adds value with no redundancy. Front-loading works well.

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 the tool's simplicity (2 optional params, no output schema, clear annotations), the description fully covers everything an agent needs: purpose, filtering semantics, return format, error cases, and comparison to siblings. No gaps remain.

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

Parameters4/5

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

Schema coverage is 100%, so baseline is 3. The description adds significant value: explains folder scopes subfolders, clarifies glob/folder combination behavior, and details glob semantics (* and **). This elevates above the baseline.

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 description clearly states the tool lists .md file paths, optionally filtered by folder or glob pattern, and explicitly says it returns paths only. This distinguishes it from sibling tools like vault_search_by_folder (which adds metadata) and vault_read_note (which reads content).

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?

The description provides explicit when-to-use guidance (browsing by filename or path pattern) and contrasts with alternatives: vault_search_by_folder for metadata, vault_search for content, and vault_read_note to read results. This helps the agent decide correctly.

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

vault_list_property_keysList Property KeysA
Read-onlyIdempotent

Discover all property keys in the vault with note counts and sample values. Lets you understand the vault's metadata schema without reading individual notes.

Example: vault_list_property_keys() returns [{ key: "tags", count: 342, sample_values: ["session-log", "project"] }, ...]

When to use: Discovering what properties exist before searching by property. Good first step for vault orientation alongside vault_list_tags. Prefer vault_list_property_values when you need the full list of values for a specific key. Prefer vault_search_by_property to find notes matching a specific key-value pair.

Parameters:

  • folder is matched as a path prefix and recurses into subfolders ("Projects" also covers "Projects/Archive"); omit it to scan the entire vault.

Returns: JSON array of { key, count, sample_values } sorted by count descending. sample_values shows the top 3 most common values per key for quick orientation.

ParametersJSON Schema
NameRequiredDescriptionDefault
folderNoRestrict to a folder (e.g. "Projects")

TDQS

A4.7/5.0
Behavior4/5

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

Annotations already declare readOnlyHint and idempotentHint; the description adds behavioral details like sorted output and sample_values top 3, plus folder recursion behavior. No contradiction.

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

Conciseness5/5

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

Well-structured: purpose with example, usage guidance, parameter explanation, return format. Front-loaded with key information, no fluff.

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 the tool's simplicity (1 param, no output schema), the description fully covers parameter behavior, output format, usage context, and sibling differentiation. Complete and actionable.

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

Parameters4/5

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

Schema description for 'folder' is minimal; the description adds crucial behavior: path prefix matching and recursion into subfolders. Schema coverage is 100%, but description adds extra value.

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 description clearly states the tool discovers all property keys with note counts and sample values, and distinguishes it from siblings like vault_list_property_values and vault_search_by_property.

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?

Explicitly states when to use as a first step for vault orientation, and provides alternatives: prefer vault_list_property_values for specific key values, and vault_search_by_property for key-value matching.

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

vault_list_property_valuesList Property ValuesA
Read-onlyIdempotent

List distinct values for a specific property key with note counts. Useful for discovering the range of values a property takes before searching.

Example: vault_list_property_values({ key: "status" }) returns [{ value: "active", count: 47 }, { value: "done", count: 211 }, ...]

When to use: Enumerating possible values for a property key before calling vault_search_by_property. Handles both scalar properties (status: "active") and array properties (tags: ["a", "b"]) — array elements are unpacked and counted individually, so the sum of counts may exceed the note count. An unknown key or empty folder returns an empty array, not an error. Call vault_list_property_keys first to discover valid key names.

Parameters:

  • key is case-sensitive and must match exactly as returned by vault_list_property_keys. Values are always strings — numeric and boolean properties are stringified for counting.

  • folder + key interact: folder restricts counting to a subtree, so the same key can return different value distributions depending on folder scope.

  • limit (default 50) applies after sorting by count descending, so you always get the most-used values first. Increase for high-cardinality keys like "title" or "created".

Returns: JSON array of { value, count } sorted by count descending.

ParametersJSON Schema
NameRequiredDescriptionDefault
keyYesProperty key name — use vault_list_property_keys to discover valid keys (e.g. "status", "type", "tags").
limitNoMax values to return (default 50). Increase for high-cardinality properties.
folderNoRestrict to a folder prefix (e.g. "Projects")

TDQS

A4.7/5.0
Behavior5/5

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

The description adds significant behavioral details beyond the annotations (which only note readOnly and idempotent). It explains how array properties are unpacked, that counts may exceed note count, that unknown keys return empty array (not error), that values are stringified, and the sorting order. This fully informs the agent of the tool's behavior.

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

Conciseness5/5

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

The description is well-structured: starts with a clear purpose, includes an example, then 'When to use' paragraph, parameter details, and return format. Every sentence adds value; no waste. Front-loaded with key information.

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 three parameters, no output schema, and good annotations, the description covers all necessary aspects: usage context, parameter interactions, edge cases, return format, sorting, and data type handling. It is fully complete for the agent to use effectively.

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

Parameters4/5

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

Schema coverage is 100%, so baseline is 3. The description adds meaningful context: key is case-sensitive and must match exactly, folder restricts subtree and interacts with key, limit applies after sorting and is suitable for high-cardinality properties. These details go beyond the schema's simple descriptions.

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 description clearly states the verb ('List distinct values'), the resource ('property key'), and the additional context ('with note counts'). It provides an example and distinguishes from siblings like vault_search_by_property and vault_list_property_keys by explicitly stating its use case: enumerating values before searching.

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

Usage Guidelines4/5

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

The description explicitly states when to use (before vault_search_by_property) and advises running vault_list_property_keys first. It covers parameter interactions (folder, key) and edge cases (unknown key, array properties). However, it does not provide an explicit list of when not to use it or compare it directly to other search tools.

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

vault_list_tagsList TagsA
Read-onlyIdempotent

List all tags in the vault with note counts, ordered by count descending. Only frontmatter tags are counted (inline #tags in note bodies are not indexed). Each hierarchical tag (e.g. "project/vault-cortex") appears as one full entry, not split into segments. Count is unique notes, not occurrences. A vault with no tagged notes returns an empty array.

Example: vault_list_tags() returns [{ tag: "session-log", count: 42 }, { tag: "project/vault-cortex", count: 8 }, ...]

When to use: Discovering what tags exist before searching by tag. Good first step for vault orientation. Prefer vault_search_by_tag once you know which tag to query — it supports hierarchical prefix matching ("project" matches "project/*").

Returns: JSON array of { tag, count } sorted by count descending. tag omits the "#" prefix; count is unique notes with this tag.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already declare readOnlyHint and idempotentHint. The description adds critical behavioral details: only frontmatter tags are counted (not inline #tags), hierarchical tags are kept intact, count is unique notes, and empty vault returns empty array. No contradiction with annotations.

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

Conciseness5/5

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

Description is concisely structured: core purpose first, then important counting rules, example, usage guidance, and return format. Every sentence adds value without redundancy.

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?

Despite no parameters and no output schema, the description fully explains behavior, edge cases (empty array), and return format (JSON array of { tag, count }). Combined with annotations, the agent has all necessary context for correct invocation.

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

Parameters4/5

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

Tool has zero parameters, so the input schema is fully covered. The description adds no parameter information (unnecessary), which is appropriate. Baseline of 4 applies per guidelines.

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 description clearly states the verb ('List') and resource ('all tags in the vault'), specifies ordering and note counts, and differentiates from the sibling vault_search_by_tag by noting it is a discovery step versus a targeted search.

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?

Provides explicit when-to-use ('Discovering what tags exist before searching by tag') and when-not-to-use ('Prefer vault_search_by_tag once you know which tag to query'), including a clear alternative tool.

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

vault_list_tasksList TasksA
Read-onlyIdempotent

List checkbox tasks across the whole vault with structured filters — the Tasks-plugin data model over MCP. Both task metadata formats are indexed: emoji signifiers (📅 due, ⏳ scheduled, 🛫 start, ➕ created, ✅ done, ❌ cancelled, 🔺⏫🔼🔽⏬ priority, 🔁 recurrence, 🆔/⛔ dependencies) and Dataview inline fields ([due:: 2026-07-04], [priority:: high], ...). Every result carries its attribution — note path, folder, line number, and the nearest heading when the task sits under one (the lane on a Kanban board) — so no follow-up reads are needed to locate a task. Task lines inside fenced code blocks and %% %% comment blocks are not indexed.

Example: vault_list_tasks({ due: { before: "2026-07-04" } }) — overdue triage; the default status (not_done) and sort (due ascending) make this the "what's overdue?" call Example: vault_list_tasks({ path: "Code Projects/vault-cortex/TASKS.md", heading: ["Active", "Up Next", "Waiting On"], sort_by: "position" }) — actionable Kanban lanes in board order; position is the natural sort for boards (file path then line number, preserving card arrangement) Example: vault_list_tasks({ folder: "Code Projects/vault-cortex" }) — all open tasks across a project tree (TASKS.md + task-notes/ subdirectories); folder is a recursive prefix match Example: vault_list_tasks({ status: "done", done: { after: "2026-06-26" } }) — what got completed this week Example: vault_list_tasks({ top_level_only: true, path: "TASKS.md" }) — board cards only, excluding checklist sub-items

When to use: Any vault-wide task triage question — "what's overdue?", "what's open per project?", "what did I finish this week?" — in one call instead of per-board reads. Prefer vault_read_note (heading mode) to read one specific board lane verbatim. Prefer vault_search for full-text queries over note content.

Parameters:

  • status: a single value or an array of values, OR-combined (default "not_done"). Values: "not_done" (todo + in_progress, excludes done AND cancelled), "todo", "in_progress", "done", "cancelled", "all". Virtual values expand in arrays: ["not_done", "done"] matches todo + in_progress + done.

  • due / scheduled / start / done / created / cancelled: date filters, each { before, on, after } in YYYY-MM-DD — before/after are exclusive, on is exact. A date filter only matches tasks that HAVE that date.

  • priority: array of "highest" | "high" | "medium" | "low" | "lowest" | "none", OR-combined ("none" = tasks with no priority signifier).

  • folder: recursive note-path prefix. tag: bare inline-task-tag name; a parent tag matches children. heading: exact heading text or array of headings, case-sensitive, OR-combined. path: one note, must end in ".md".

  • top_level_only: boolean (default false). When true, only top-level tasks (depth 0) are returned — excludes indented sub-tasks and checklist items.

  • sort_by: "due" (default) | "scheduled" | "start" | "created" | "done" | "priority" | "note_mtime" | "position". "position" sorts by file path then line number — the natural order for Kanban boards.

  • limit: max results (default 50). The total field always reports the full match count.

Errors:

  • A malformed or calendar-invalid date filter throws with remediation text ("Use YYYY-MM-DD")

  • path without the ".md" extension is rejected

  • No matches returns { total: 0, tasks: [] }, not an error

Returns: JSON { total, tasks }. Every task carries path, line, status, status_char, description, folder, depth (0 for top-level, 1+ for sub-tasks), is_kanban_task, depends_on, and tags (the arrays are [] when empty). Every other field appears only when the task has it: heading (nearest heading above the task), created/scheduled/start/due/done/cancelled dates, priority, recurrence, on_completion, task_id, block_id, parent_block_id (sub-tasks whose parent carries a ^block-id), done_lanes (Kanban boards only).

ParametersJSON Schema
NameRequiredDescriptionDefault
dueNoDue date (📅 / [due:: ]) bounds
tagNoInline task tag, bare name without "#"; parent tags match children
doneNoDone date (✅ / [completion:: ]) bounds
pathNoRestrict to one note (vault-relative path ending ".md")
limitNoMax results (default 50); total always reports the full match count
startNoStart date (🛫 / [start:: ]) bounds
folderNoRestrict to a note-path prefix (e.g. "Code Projects/vault-cortex")
statusNoStatus filter, OR-combined (default "not_done" = todo + in_progress, excluding done and cancelled). Virtual values expand in arrays: "not_done" adds todo + in_progress, "all" includes every status.
createdNoCreated date (➕ / [created:: ]) bounds
headingNoExact heading text or array of headings, OR-combined, case-sensitive (e.g. "Active" or ["Active", "Up Next"])
sort_byNoSort key (default "due"). Date sorts cascade through related fields when the primary is absent; each fallback uses its own natural direction. "position" sorts by file path then line number — the natural order for Kanban boards.
priorityNoPriority levels, OR-combined; "none" selects tasks with no priority signifier
cancelledNoCancelled date (❌ / [cancelled:: ]) bounds
scheduledNoScheduled date (⏳ / [scheduled:: ]) bounds
sort_directionNoSort direction. Default per field: "asc" for due/scheduled/priority/position, "desc" for start/created/done/note_mtime. Within a date cascade, each fallback uses its own default; an explicit value overrides all fields uniformly.
top_level_onlyNoWhen true, only top-level tasks (depth 0) are returned — excludes indented sub-tasks and checklist items. Default false.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false, and the description adds substantial behavioral context: it discloses that fenced code blocks and %% %% comment blocks are not indexed, that no follow-up reads are needed to locate a task, that no matches returns an empty result rather than an error, and that invalid date filters throw remediation text. This goes well beyond the annotation baseline and contains no contradictions.

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 the length is justified by 16 parameters and no output schema. It is front-loaded with purpose, then examples, then parameter and error sections, making it scannable. Some parameter text overlaps with the schema's own descriptions, but the examples and error/return details earn their place.

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?

For a complex tool with 16 parameters, nested date objects, and no output schema, the description is exceptionally complete: it covers default values, sort semantics, error behavior, empty-result behavior, indexing exclusions, and the full return shape with which fields are conditional. An agent has everything needed to invoke it correctly.

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

Parameters4/5

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: it explains that date filters only match tasks that actually have that date, that 'position' is the natural Kanban order, that 'not_done' excludes done and cancelled, and it provides five concrete usage examples showing parameter combinations. This meaningfully enriches the structured schema definitions.

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 description opens with a precise verb and resource: 'List checkbox tasks across the whole vault with structured filters.' It clearly distinguishes itself from siblings by explicitly naming vault_read_note and vault_search as the alternatives for other use cases, so an agent can select it correctly without inspecting other tool schemas.

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?

The 'When to use' section gives concrete scenarios ('what's overdue?', 'what's open per project?', 'what did I finish this week?') and explicitly says to prefer vault_read_note for reading a board lane verbatim and vault_search for full-text content queries. This is strong routing guidance with both inclusion and exclusion criteria.

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

vault_memory_recallMemory RecallA
Read-onlyIdempotent

Recall memory entries about a topic — entry-granular hybrid (keyword + semantic) retrieval across ALL About Me/ files and ALL time. Returns every relevant dated entry sorted oldest-first, so the full evolution of a preference, opinion, or fact is visible — semantic matching finds early entries even when their phrasing differs from the query. Tuned for recall over precision: expect some marginal entries and judge relevance yourself when synthesizing an answer. Content-word queries ("testing philosophy", "sustainable pacing") rank best; a meta-framed query ("opinions on testing") whose relevance cut would come back empty degrades to relaxed any-term keyword matching instead of returning nothing.

Example: vault_memory_recall({ query: "working hours and pacing" }) Example: vault_memory_recall({ query: "opinions on testing", file: "Opinions" })

When to use: Answering "what does my memory say about X?" or "how has my view on Y evolved?" — topic-based recall across memory files. Prefer vault_get_memory to read a known file or section verbatim; prefer vault_search for notes outside the memory layer.

Errors:

  • No matching entries returns { entries: [], total: 0 }, not an error

  • An unknown file returns empty results — call vault_list_memory_files to discover valid names

Returns: JSON { entries, total, truncated, search_mode, reranked }. Each entry is { file, section, date, text } — text is the raw entry markdown (wikilinks intact, continuation lines included); file and section feed directly into vault_get_memory or vault_delete_memory. entries ascend by date (oldest first). total counts all matched entries; truncated=true means max_results dropped the least-relevant matches — never a date range — so raise max_results or narrow the query for the complete set. search_mode is "hybrid" when vector matching contributed, "fts" when the entries came from keyword matching alone — including the any-term fallback that rescues a would-be-empty result; reranked is true when the cross-encoder relevance cut was applied.

ParametersJSON Schema
NameRequiredDescriptionDefault
fileNoOptional: restrict to one memory file, name without .md (e.g. "Opinions"). Omit for cross-file recall — the default and usual choice.
queryYesTopic to recall — natural language works best (semantic matching bridges phrasing drift across months); content words about the topic rank better than meta framing ("testing philosophy" over "opinions on testing")
max_resultsNoCap on returned entries (default 50). When more match, the least-relevant are dropped and truncated=true — never a date range.

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already indicate readOnlyHint=true, destructiveHint=false, and idempotentHint=true. The description adds behavioral details beyond annotations: that the tool is tuned for recall over precision (expect marginal entries), that search_mode can be 'hybrid' or 'fts' with an any-term fallback to avoid empty results, that reranked indicates a relevance cut, and that truncated=true means least-relevant matches dropped (not a date range). No contradiction.

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 multi-paragraph but each sentence adds necessary information. It front-loads the core purpose and usage, then details behavior, errors, and return format. While not terse, it avoids redundancy and every sentence appears justified for a tool with this complexity.

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?

Despite lacking an output schema, the description fully explains the return value: JSON with entries, total, truncated, search_mode, reranked. Each entry's fields (file, section, date, text) are described, including text containing raw markdown. Edge cases (empty results returning {entries:[], total:0}, unknown file returning empty) are covered. This is complete for a read-only, idempotent tool.

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% with descriptions for all 3 parameters. The description adds significant value: for 'query' it explains natural language works best and contrasts content words vs meta framing with examples; for 'file' it clarifies omission means cross-file; for 'max_results' it explains truncation behavior. This goes well beyond the schema alone.

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 description clearly states the verb 'recall' and the resource 'memory entries'. It specifies entry-granular hybrid retrieval across all About Me/ files and all time, and distinguishes from sibling tools like vault_get_memory (for known files/sections) and vault_search (for notes outside the memory layer).

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?

Explicit guidance is given: 'Answering "what does my memory say about X?" or "how has my view on Y evolved?"' as when to use, and 'prefer vault_get_memory to read a known file or section verbatim; prefer vault_search for notes outside the memory layer' as when-not and alternatives. Error behavior for empty results and unknown file is also documented.

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

vault_move_noteMove NoteA
Destructive

Move or rename a note and rewrite every link across the vault that points to it, like Obsidian's built-in rename. Incoming links in other notes — [[wikilinks]], [[wikilink|aliases]], [[wikilink#headings]], ![[embeds]], markdown, and frontmatter links (e.g. related:) — are updated to the new path; the moved note's own relative links are fixed so they still resolve from the new folder, including relative links to attachments (e.g. ![[../assets/photo.png]], img). A link is only rewritten when leaving it unchanged would break it, so a short [[Note]] that stays unambiguous after a folder move is left alone. Without this tool a move silently breaks every backlink.

Example: vault_move_note({ old_path: "Inbox/Draft.md", new_path: "Inbox/Spec.md" }) — pure rename. Example: vault_move_note({ old_path: "Inbox/Spec.md", new_path: "Projects/Spec.md" }) — move to another folder, updating links and the note's own relative links. Example: vault_move_note({ old_path: "Inbox/Spec.md", new_path: "Projects/Spec.md", prune_empty_folders: true }) — also remove "Inbox" if the move empties it.

When to use: Renaming a note or relocating it to a different folder while keeping the link graph intact. Prefer this over vault_write_note + vault_delete_note, which would orphan every backlink. To only change a note's body or properties, use vault_patch_note or vault_update_properties. Protected paths (About Me/ and the daily notes folder (read from DAILY_NOTES_FOLDER or .obsidian/daily-notes.json, defaulting to Daily Notes/)) cannot be moved.

Errors:

  • "destination exists: …" — a note already lives at new_path; this tool never overwrites. Pick a free path or delete the existing note first.

  • "note not found: …" — old_path does not exist; verify it with vault_list_notes.

  • "cannot move protected path …" / "cannot move into protected path …" — old_path or new_path sits under a protected folder.

  • "path must end in …" — old_path or new_path is missing the .md extension; both paths must end in .md.

  • "path traversal blocked" — a path escapes the vault root; use vault-relative paths.

  • "hidden path blocked" — old_path or new_path targets a hidden (dot-prefixed) file or folder like ".obsidian/"; notes cannot be moved from or into hidden paths, matching Obsidian.

  • "concurrent write in progress" — a write is in flight on the note, the destination, or one of its backlink sources (the move locks all of them as one unit); retry the move.

  • "backlink set did not stabilize" — the vault was modified during the move and new backlink sources kept appearing across retries; nothing was written; retry the move.

  • Mid-move I/O failure (rare, e.g. a permission or disk error while writing) — the move aborts and the original note is deleted only after the destination and all backlinks are written, so a failure never loses data. The error message names what failed and the resulting state: if a backlink write failed, new_path exists and the original is intact (re-run the move, deleting the partial new_path first, to finish); if the final delete failed, both old_path and new_path exist (delete old_path to finish).

Obsidian syntax: Link rewrites preserve each link's existing form — embed marker (!), heading anchor (#…), and alias (|…) are kept; a markdown link keeps its original extension and link text. Only the target path is changed.

Returns: JSON with moved_to (the new path), links_updated (count of link occurrences rewritten), updated_notes (sorted paths of the other notes that were edited; the moved note is implied by moved_to), and pruned_empty_folders (count of source folders removed — 0 unless prune_empty_folders was set).

ParametersJSON Schema
NameRequiredDescriptionDefault
new_pathYesDestination vault-relative path (e.g. "Projects/Spec.md"). Must end in .md and must not already exist; parent folders are created as needed.
old_pathYesCurrent vault-relative path of the note to move (e.g. "Inbox/Draft.md"). Must end in .md.
prune_empty_foldersNoWhen true, remove the source folder(s) if the move leaves them empty, walking up to (but never including) the vault root. Default false matches Obsidian, which leaves empty folders in place. Only removes a folder with zero entries — an in-place rename or a move into a subfolder of the source leaves it non-empty and prunes nothing.

TDQS

A4.9/5.0
Behavior5/5

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

Even though destructiveHint=true already signals mutation, the description goes far beyond it: it explains link-rewriting semantics, the no-overwrite guarantee, protected paths, hidden path blocking, concurrency locking, and detailed failure recovery behavior (e.g., 'a failure never loses data'). It even discloses partial-failure states and how to recover, which is exactly the kind of beyond-annotation context an agent needs.

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

Conciseness5/5

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

The description is long but tightly organized into purposeful sections: intro, examples, when-to-use, errors, syntax notes, and return value. Every section earns its place, especially for a destructive operation with link rewriting and failure cases. The core purpose is front-loaded, with supporting detail following a logical order.

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 the complexity of the operation—link graph rewriting, protected paths, failure recovery, and pruning—the description is complete. There is no output schema, but the description documents the return shape (moved_to, links_updated, updated_notes, pruned_empty_folders). It also catalogues the full error surface, so an agent can anticipate and respond to failures.

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

Parameters4/5

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 genuinely adds value: it supplies concrete examples for pure rename, folder move, and prune behavior, and clarifies the prune_empty_folders semantics (walking up but never including vault root, only removing zero-entry folders). This exceeds the schema's own parameter descriptions without repeating them verbatim.

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 description opens with a specific verb and resource: 'Move or rename a note and rewrite every link across the vault that points to it,' which immediately establishes both the action and its scope. It also references Obsidian's built-in rename, giving the agent an unambiguous mental model. This clearly distinguishes it from sibling read/write/delete tools.

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?

The 'When to use' section explicitly states the intended scenario and names the alternative: 'Prefer this over vault_write_note + vault_delete_note, which would orphan every backlink.' It also tells the agent when to choose other tools ('To only change a note's body or properties, use vault_patch_note or vault_update_properties'). This is explicit routing guidance with no reliance on inference.

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

vault_patch_notePatch NoteA
Destructive

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 rename a heading if they 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

  • "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.

ParametersJSON 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.

TDQS

A5/5.0
Behavior5/5

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

Annotations already mark the tool as destructive, but the description adds substantial behavioral context: frontmatter preservation, possible YAML normalization, non-atomic write ordering, heading boundary semantics, hidden path blocking, concurrent write errors, and the risk of replace destroying child headings. It even describes what happens when a no-heading prepend accidentally nests existing content.

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

Conciseness5/5

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

The description is long, but the tool is genuinely complex with four operations, multiple edge cases, and an extensive error surface. It is well-structured with bolded section labels, a front-loaded overview, explicit examples, an organized error list, and a clear returns section, so an agent can quickly scan for relevant details.

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?

The description covers every documented error, return format, operation-specific constraint, alternative-tool routing, and even an example call. Since there is no output schema, the explicit return message description is necessary and sufficient. Nothing required for correctly invoking the tool is missing.

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?

Although input schema coverage is 100%, the description goes well beyond the schema by explaining operation-specific behavior, heading matching semantics, heading_level disambiguation, include_children confirmation, table-row handling, and leading-callout editing. This adds real meaning to parameters like operation, heading, content, and include_children rather than just restating the schema.

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 description opens with a specific verb phrase and resource: 'Surgical edits to a markdown note' and immediately enumerates the four operations: append, prepend, replace, or insert content by heading. It also distinguishes itself from siblings by explicitly naming vault_write_note, vault_replace_in_note, and vault_delete_span as alternatives.

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?

The description includes an explicit 'When to use' section and states when to prefer vault_write_note and vault_replace_in_note instead. It also provides a step-by-step cross-section move workflow with read, patch, replace/delete, and retry guidance, making the selection and invocation conditions unambiguous.

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

vault_read_fileRead FileA
Read-onlyIdempotent

Read a non-markdown vault file in its most useful form per type — the read-side companion to vault_read_note for everything that isn't a note.

Example: vault_read_file({ path: "attachments/diagram.png" }) — the image itself, shrunk to fit response limits when needed Example: vault_read_file({ path: "Boards/Roadmap.canvas" }) — a readable outline of the canvas Example: vault_read_file({ path: "Boards/Roadmap.canvas", raw: true }) — the canvas's exact JSON source Example: vault_read_file({ path: "exports/data.json" }) — the file content as text Example: vault_read_file({ path: "exports/big.csv", limit: 500 }) — the first 500 lines, preceded by a metadata line stating the window and total line count Example: vault_read_file({ path: "papers/research.pdf" }) — structured text with title, headings, and links Example: vault_read_file({ path: "papers/research.pdf", raw: true }) — each page rendered as an image block

What each type returns:

  • Images (.png/.jpg/.jpeg/.gif/.webp): the image as a viewable image block — downscaled and recompressed server-side when it exceeds client response limits, delivered untouched otherwise — plus a text line stating the path, delivered format/dimensions/bytes, and the original dimensions when shrunk. Animated GIFs are reduced to their first frame when recompressed to fit the budget.

  • Canvas (.canvas): a readable markdown outline per JSON Canvas 1.0 — groups (by visual containment), node content in reading order, and a connections list with edge labels. Set raw: true for the exact JSON source instead (geometry, ids, colors — full fidelity).

  • PDFs (.pdf): structured text with document metadata — title, page count, heading hierarchy (from font sizes relative to the body text), code blocks and inline code (from monospace fonts), page separators, and a deduplicated links footer. Richer than flat text extraction: headings, code, and hyperlinks that flat extraction loses are preserved. Set raw: true for page images instead — each page rendered and returned as an image block, showing layout, diagrams, tables, and formatting that text extraction cannot preserve. Image-only and scanned PDFs work in raw mode. Up to 5 pages are rendered.

  • Text formats (.svg/.json/.txt/.csv/.xml/.log/.yaml/.yml/.base): the file content verbatim as text. .svg is returned as its XML source; .base as its YAML source.

  • Line paging: start_line and limit page any text result — text formats, canvas outlines and raw JSON, PDF-extracted text — as a 1-based line window, preceded by a metadata line ("data.csv — lines 51–100 of 400 (continue with start_line: 101)"). Paged windows come back with \n line endings and no trailing newline; a read without paging inputs stays byte-exact.

When to use: whenever a note references a file you need to actually see or read — an embedded diagram, a linked canvas, data file, or PDF. Find the files a note links to (with byte sizes) via vault_get_outgoing_links; browse a folder's files via vault_list_files. For .md notes use vault_read_note — this tool rejects them. To check a large file's size before reading it whole, request start_line: 1 with limit: 1 — one line plus the total line count.

Errors:

  • "not a file" — the path ends in .md; read notes with vault_read_note

  • "file not found" — nothing exists at that path; discover valid paths via vault_list_files

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

  • "file too large" — the file exceeds the server's read cap (MAX_FILE_BYTES, default 50 MiB)

  • "text output too large" — a text file or PDF renders past the output cap; page it with start_line and limit, or reduce limit when a single window overflows

  • "start line past the end" — start_line exceeds the file's line count; the error states the total, so retry with a smaller start_line

  • "line range is not available" — start_line/limit on an image or on a PDF with raw: true; line paging applies to text results only

  • "not valid UTF-8" — the file's bytes aren't UTF-8 text; returning them would silently corrupt the content

  • "PDF has no extractable text" — the PDF exists but contains no text content (scanned or image-only); states the page count. Set raw: true to render pages as images instead

  • "PDF page rendering failed" — raw: true was set but no pages could be rendered; the PDF may be corrupt

  • "image cannot be fitted" — the image could not be compressed under the output budget (MAX_IMAGE_OUTPUT_BYTES)

  • "raw source is not available for images" — raw applies to text-representable files; an image's delivered form is its image block

  • unsupported types (audio, archives, …) return an error naming the readable types plus the file's existence and size

Returns: for images, an image content block plus a one-line metadata text block; for PDFs with raw: true, a metadata text block followed by alternating image and text blocks (one pair per page); for every other supported type, a single text content block — preceded by a window-metadata text block when start_line or limit was given.

Search coverage: vault_search indexes markdown notes plus canvas, PDF, and supported text-format content; find other files by browsing (vault_list_files) or through a note's links (vault_get_outgoing_links).

ParametersJSON Schema
NameRequiredDescriptionDefault
rawNoReturn an alternative representation of the file. For .canvas this is the JSON Canvas source (geometry, ids, colors); for .pdf this renders pages as images instead of extracting text — useful for scanned documents, diagrams, and layout-sensitive content. Text formats already return their source, so raw changes nothing there. Images have no text source — raw returns an error.
pathYesVault-relative path to the file, including its extension (e.g. "attachments/photo.png", "Boards/Roadmap.canvas"). Must NOT end in ".md" — notes are read with vault_read_note.
limitNoMaximum lines returned (default: all remaining). A paged read's metadata line states the window, the total line count, and the next start_line. The output byte cap still applies to the window — reduce limit if it overflows.
start_lineNoFirst line to return, 1-based (default 1). Pages any text result — text formats, canvas outlines and raw JSON, PDF-extracted text. Not valid for images or for PDFs with raw: true.

TDQS

A4.4/5.0
Behavior5/5

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

The description goes far beyond the annotations (which already declare idempotentHint=true, readOnlyHint=true). It details how images are downscaled/recompressed, how animated GIFs are handled, how PDFs are extracted (including heading hierarchy and code blocks), line-paging behavior, and the exact format of error messages. This is exceptionally exhaustive for a read-only tool.

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

Conciseness2/5

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

The description is extremely long and contains a lot of detailed behavior, error explanations, and returns information that, while useful for behavioral completeness, could be shortened or moved to tool-specific documentation. The examples at the top are helpful, but the error list in particular is verbose. In its current form, it is not concise.

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?

For a tool with 4 parameters (100% schema description), clear annotations, no output schema, and a complex domain (multiple file types with different behaviors), the description provides exhaustive coverage: per-type return formats, paging details, error messages, search coverage, and relationships to sibling tools. It leaves no question unanswered about what the tool does or how it behaves.

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

Parameters3/5

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

Schema description coverage is 100%, so the baseline is 3. The description restates some parameter semantics (e.g., raw behavior for canvas and PDF, start_line/limit paging) but does not significantly add beyond what the schema descriptions already provide. The examples in the description are valuable context but the parameter schema is already complete and well-documented.

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 description is extremely precise: 'Read a non-markdown vault file in its most useful form per type.' It immediately distinguishes itself from vault_read_note (which handles .md files). The description also lists all supported types and their behavior, leaving no ambiguity about the tool's scope.

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?

The description explicitly states when to use this tool ('whenever a note references a file you need to actually see or read'), when not to use it ('For .md notes use vault_read_note — this tool rejects them'), and how to find files to read (vault_get_outgoing_links, vault_list_files). It also provides guidance on efficient usage ('To check a large file's size... request start_line: 1 with limit: 1').

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

vault_read_noteRead NoteA
Read-onlyIdempotent

Read a markdown note by its vault-relative path. By default returns the full raw content including properties; optional modes return just the properties, just the heading outline, or just one section — so large notes don't blow the token budget.

Example: vault_read_note({ path: "Projects/vault-cortex.md" }) Example: vault_read_note({ path: "Projects/vault-cortex.md", properties_only: true }) Example: vault_read_note({ path: "TASKS.md", outline: true }) Example: vault_read_note({ path: "TASKS.md", heading: "Active" }) Example: vault_read_note({ path: "TASKS.md", heading: "Done", heading_level: 2 }) // disambiguate when several "Done" headings exist Example: vault_read_note({ path: "TASKS.md", heading: "Done", start_line: 1, limit: 20 }) // first 20 lines of an oversized section

When to use: You know the exact path and need a specific note's content. For a large note (a long board or doc), use outline: true to see its headings and any text sitting above them, then heading: "..." to read just the one section you need — both far cheaper than pulling the whole file. Use properties_only: true when you only need properties. For an oversized note or section, page it with start_line and limit to read a window at a time. To check a note's or section's line count, request start_line: 1 with limit: 1 — one line plus the total. Prefer vault_search when you don't know the path. Prefer vault_get_memory for About Me/ files (returns content without properties). To edit a section you've read, use vault_patch_note. To explore what links to this note or what it links to, use vault_get_backlinks and vault_get_outgoing_links.

Section boundaries: a section spans from its heading to the next heading of the same or higher level (or EOF). Child headings are included. Modes are mutually exclusive — set at most one of properties_only, outline, or heading. Paged reads normalize line endings to LF; unpaged reads stay byte-identical.

Errors:

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

  • "ambiguous heading" — multiple headings match; use heading_level to disambiguate

  • "outline, heading, and properties_only are mutually exclusive" — only one mode per call

  • "line paging is not available in outline mode" / "... properties_only mode" — start_line/limit only work on text renditions (full read or heading section)

  • "start line past the end" — start_line exceeds the rendition's line count; error states the total

  • 'path must end in ".md"' — the path names a non-markdown file; read files (images, .canvas, data files) with vault_read_file instead

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

Returns: Raw markdown string (default); JSON object of properties (properties_only); JSON outline object (outline); raw markdown of the section, heading line included (heading). When start_line or limit is given, the result is preceded by a window-metadata text block ("path — lines 1–20 of 250 (continue with start_line: 21)").

Outline shape: { leading_callout?, leading_content?, headings } — headings is [{ level, text, bytes }]; leading_callout ({ type, title, body }) is the note's top-of-file callout; leading_content is the rest of the body text above the first heading, with the callout's own lines excluded so the two never repeat the same text. Either key is omitted when the note has none. Empty headings ("##" with no text) appear with text: "" — they act as section boundaries but cannot be targeted by the heading parameter; read the parent section (which includes child headings) or the full note, and edit via vault_replace_in_note.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesVault-relative path to the note, including the ".md" extension (e.g. "About Me/Principles.md")
limitNoMaximum lines returned (default: all remaining). A paged read's metadata line states the window, the total line count, and the next start_line.
headingNoReturn only this section (heading line + body, through the next same-or-higher heading). Case-sensitive exact match.
outlineNoIf true, returns { leading_callout?, leading_content?, headings } as JSON instead of body content — a cheap structure fetch for large notes. headings: [{ level, text, bytes }]; leading_callout: { type, title, body } when the note has a top-of-file callout; leading_content: the rest of the body text above the first heading (callout lines excluded) when the note has any.
start_lineNoFirst line to return, 1-based (default 1). Pages the delivered rendition (full body or a heading section). Not valid for outline or properties_only (JSON modes).
heading_levelNoHeading level (1-6) for disambiguation when multiple headings share the same text; only applies with heading
properties_onlyNoIf true, returns parsed properties as JSON instead of full note content

TDQS

A5/5.0
Behavior5/5

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

Annotations declare readOnlyHint, idempotentHint, and destructiveHint=false, confirming safe read behavior. The description adds rich behavioral context beyond annotations: default returns full raw content including properties, mutual exclusivity of modes, line ending normalization during paging, section boundary definitions, detailed error messages, and access restrictions (hidden paths blocked). No contradictions with annotations.

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

Conciseness5/5

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

Well-structured with clear sections: examples, when-to-use, section boundaries, errors, and return value shape. Every sentence adds value—no filler. Essential details are front-loaded (main behavior then examples). The error list is comprehensive yet concise.

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 the tool's complexity (7 parameters, 3 mutually exclusive modes, paging, multiple return formats) and absence of output schema, the description is exceptionally complete. It covers return shapes (raw markdown, JSON for properties/outline, window metadata), error scenarios, and boundary behavior—all necessary for correct agent usage without needing an output schema.

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 description coverage is 100%, and the description goes well beyond by providing practical usage patterns: outline returns a specific JSON structure with leading_callout and leading_content, paging adds window metadata, heading_level disambiguates when headings share text, and start_line with limit pages the rendition. The description adds context not present in schema descriptions, such as starting line 1 with limit 1 to get total line count.

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 description clearly states it reads a markdown note by vault-relative path. It distinguishes itself from siblings like vault_search, vault_get_memory, vault_read_file, and vault_patch_note with explicit examples and when-to-use guidance. The verb 'read' combined with the resource 'markdown note' is specific and actionable.

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?

Provides explicit when-to-use and when-not-to-use guidance, including preferring vault_search without a known path, vault_get_memory for 'About Me/' files, vault_patch_note for editing, and vault_get_backlinks/vault_get_outgoing_links for link exploration. Also gives detailed strategies for large notes (outline, heading, paging) and line count checking.

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

vault_recent_notesRecent NotesA
Read-onlyIdempotent

List recently modified or created notes, sorted by timestamp — a time-ordered window into the vault, not a date-range filter.

Example: vault_recent_notes({ sort_by: "modified", limit: 10 }) Example: vault_recent_notes({ sort_by: "created", limit: 5 })

When to use: Catching up on vault changes, finding recent work, or orienting after a break. Prefer vault_search for content-based discovery. Prefer vault_search_by_folder for browsing a specific folder.

Parameters:

  • sort_by + limit interact: "modified" (default) uses filesystem mtime, so every note has a value and limit works predictably. "created" uses the frontmatter created property — notes without it sort last (not excluded), so a small limit may return only notes that have the property; increase limit or use "modified" for broader coverage.

  • "modified" includes any file write (content edits, property changes, sync touches), so recently-synced notes appear recent even without user edits.

Errors:

  • An empty vault returns an empty array, not an error.

Returns: JSON array of note metadata (path, title, tags, related, folder, type, created, modified, bytes, leading_callout?, additional_properties), sorted descending by chosen timestamp. created is null when the property is missing; bytes is on-disk file size.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax results (default 20, no upper cap)
sort_byNoSort order (default "modified")

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already show readOnlyHint, idempotentHint, destructiveHint. The description adds context: explains mtime vs frontmatter behavior, notes without 'created' sort last, empty vault returns empty array, and that 'modified' includes sync touches. No contradictions.

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 well-structured with purpose first, then examples, usage, parameter details, errors, returns. It's slightly long but every sentence adds value. Could be more concise but still effective.

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 the tool's simplicity (2 params, no output schema), the description covers purpose, usage, parameter behavior, edge cases (empty vault), and return format (listing fields). It is complete for an AI agent to use correctly.

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%, but the description adds meaning: interaction between sort_by and limit, behavior when property missing, defaults, and that 'modified' includes sync touches. This adds significant value beyond the schema.

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 description clearly states the tool lists recently modified/created notes sorted by timestamp, and distinguishes itself from a date-range filter. It provides examples and differentiates from sibling tools like vault_search and vault_search_by_folder.

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?

Explicitly says when to use (catching up, finding recent work, orienting) and when not to (prefer vault_search for content, vault_search_by_folder for browsing). This is excellent guidance.

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

vault_replace_in_noteReplace in NoteA
Destructive

Find and replace text in a markdown note's body. Matches exact text (case-sensitive). Properties are preserved; YAML formatting may be normalized to block style on first edit. Operates on the body only — properties must be edited via vault_update_properties or vault_write_note's properties parameter.

Example: vault_replace_in_note({ path: "Projects/plan.md", old_text: "TODO: write summary", new_text: "Summary complete." })

When to use: Targeted text changes within a single location — fixing typos, updating values, renaming terms, or removing a short line (new_text=""). Replaces text in place; does not move content across sections. To delete a large multi-line block, prefer vault_delete_span (short anchors instead of full old_text). To replace a large block by anchors instead of reproducing the full old_text, use vault_replace_span. To relocate content between headings, vault_patch_note to add at the target first, then remove from source (new_text="") — add-before-delete, so a failure duplicates the block instead of losing it.

Parameters:

  • old_text is matched in the body only — frontmatter properties are never searched. Include enough surrounding context to ensure uniqueness when the target text appears in multiple places.

  • old_text + new_text together determine the operation: a non-empty new_text is an edit; an empty new_text ("") is a deletion. No regex — exact text only.

  • replace_all_occurrences (default false) replaces only the first match — a safety default when old_text appears in multiple places. Set true for deliberate bulk renames or term replacements.

Errors:

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

  • "text not found" — old_text does not appear in the note body; verify exact text with vault_read_note

  • "oldText cannot be empty" — old_text must be at least one character

  • "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

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

Obsidian syntax: new_text is Obsidian Flavored Markdown (no escaping applied). Watch for: #word = tag, [[ = wikilink, %% = comment block in replacement text.

Returns: Confirmation message with replacement count (number of occurrences replaced).

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesVault-relative path to the note, including the ".md" extension (e.g. "Projects/plan.md")
new_textYesReplacement text. Empty string ("") deletes the matched text.
old_textYesExact text to find (case-sensitive). Matches in the body only — text inside frontmatter properties is not searched.
replace_all_occurrencesNoReplace all occurrences (default: false — replaces first occurrence only)

TDQS

A4.9/5.0
Behavior5/5

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

Even though annotations already indicate a destructive, non-idempotent mutation, the description adds substantial behavioral context: YAML formatting may be normalized to block style, only the body is searched, replacement defaults to first occurrence only, there is no regex, Obsidian Flavored Markdown is interpreted with no escaping, and error cases are enumerated. This goes well beyond what annotations convey.

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

Conciseness5/5

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

The description is long but meticulously structured with sections for usage, parameters, errors, and syntax, and the core behavior and example are front-loaded. Every sentence carries operational or routing information; nothing is filler.

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?

There is no output schema, so the description correctly explains the return value (confirmation with replacement count). It also covers failure modes, behavior with hidden paths, concurrency, and Obsidian syntax implications. An agent has everything needed to call and interpret this destructive tool correctly.

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

Parameters4/5

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

The schema already covers all four parameters with high-quality descriptions, so the bar is the extra meaning. The description adds value by explaining that old_text and new_text together determine edit versus deletion, advising contextual uniqueness for old_text, and framing replace_all_occurrences as a safety default versus deliberate bulk rename. This is more than baseline but somewhat duplicative of the schema.

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 description opens with a specific verb and resource: 'Find and replace text in a markdown note's body.' It immediately bounds the scope ('Operates on the body only') and distinguishes the tool from sibling span-deletion/replacement tools, so an agent knows exactly what this tool is and is not.

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?

It has an explicit 'When to use' section that names targeted single-location edits and gives concrete alternatives with rationale: vault_delete_span for large multi-line deletions, vault_replace_span for anchor-based replacement, and vault_patch_note for relocating content. It also routes property edits to vault_update_properties or vault_write_note. This fully satisfies the when-to-use versus when-not-to-use requirement.

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

vault_replace_spanReplace SpanA
Destructive

Replace a contiguous block of whole lines in a note's body with new content, identified by short anchor substrings instead of the block's full text. Each anchor locates a full line — the entire line is selected, not just the matching substring. Same anchor semantics as vault_delete_span. Case-sensitive matching. Properties are preserved; YAML formatting may be normalized to block style on first edit. Operates on the body only.

Example: vault_replace_span({ path: "Tracker.md", start_anchor: "| 2024-03-02 | Acme", content: "| 2024-03-02 | Acme Corp | Updated |" }) — replaces the one table row whose line contains that fragment. Example: vault_replace_span({ path: "Notes/Plan.md", start_anchor: "> [!warning] Stale", end_anchor: "remove after launch", content: "> [!info] Current\n> Updated for v2." }) — replaces the callout block with a new one.

When to use: Replacing a block you have already read — a table row, callout, or run of list items — where reproducing it exactly as old_text would be error-prone. Pick a short, unique fragment of the first line for start_anchor and, for a multi-line block, the last line for end_anchor. Prefer vault_replace_in_note for small in-place text changes (typos, renaming). Prefer vault_delete_span when removing without replacement.

Parameters:

  • start_anchor + end_anchor define a line range, not a text range — each anchor locates a full line, and the entire line from start to end is replaced (never cuts mid-line). Omit end_anchor for a single-line replace.

  • end_anchor is searched at or after the start line, so the span can never run backward. If both match the same line, only that one line is replaced.

  • content replaces the entire matched span and must be non-empty. A trailing newline adds a blank line after the new block.

  • first_match applies to both anchors independently — when an anchor matches multiple lines, takes the first instead of erroring.

  • Blank-line runs left by the replacement are collapsed to a single blank line.

Errors:

  • "note not found" — verify path with vault_list_notes

  • "anchor not found" — fragment not on any line; verify with vault_read_note

  • "ambiguous start anchor …" / "ambiguous end anchor …" — the anchor matches multiple lines; use a longer fragment or set first_match: true

  • "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.

Returns: Confirmation message "Replaced lines with lines in " — N counts the lines the span covered, M the lines content supplied.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesVault-relative path to the note, including the ".md" extension (e.g. "Tracker.md", "Notes/Plan.md")
contentYesReplacement content (one or more lines) — replaces every line of the matched span. Must be non-empty; use vault_delete_span to delete without replacement.
end_anchorNoShort, unique substring that identifies the LAST line of the block, searched at or after the start_anchor line. The entire line is selected. Omit to replace just the single line containing start_anchor.
first_matchNoIf an anchor matches more than one line, use the first match instead of erroring (default: false — ambiguity is an error).
start_anchorYesShort, unique substring that identifies the first line of the block (case-sensitive). The entire line is selected, not just the substring. Pick a brief fragment — do not paste the whole block.

TDQS

A5/5.0
Behavior5/5

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

The annotations only signal destructiveHint=true, but the description adds substantial behavioral context: whole-line selection, case-sensitive matching, properties preserved, YAML formatting may be normalized to block style, blank-line runs collapsed, end_anchor cannot run backward, and first_match applies independently to both anchors. It even describes the exact confirmation return message.

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

Conciseness5/5

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

The description is long but tightly structured with clear sections: opening behavior statement, examples, when-to-use, parameter semantics, error list, and Obsidian syntax caveats. Every sentence adds operational value; nothing is filler or tautological.

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?

For a complex span-replacement tool with no output schema, the description is complete: it covers line-range semantics, anchor matching, error conditions, return message format, and Obsidian markdown escaping behavior. The tool can be invoked correctly without needing additional documentation.

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?

Even though schema coverage is 100%, the description meaningfully enriches the schema: start_anchor/end_anchor define a line range rather than a text range, the span never cuts mid-line, omitting end_anchor means single-line replacement, trailing newline in content adds a blank line, and first_match applies independently to each anchor. The examples demonstrate realistic parameter combinations.

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 description opens with a specific verb and resource: 'Replace a contiguous block of whole lines in a note's body with new content, identified by short anchor substrings.' It clarifies the tool targets full lines rather than arbitrary text, distinguishes it from vault_delete_span and vault_replace_in_note, and provides concrete examples showing exact usage.

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: use this tool when replacing a block you've already read and reproducing the full text as old_text would be error-prone. It also names alternatives directly: 'Prefer vault_replace_in_note for small in-place text changes' and 'Prefer vault_delete_span when removing without replacement.'

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

vault_search_by_folderSearch by FolderA
Read-onlyIdempotent

Browse notes in a folder with full metadata (tags, type, related, created, modified) — unlike vault_list_notes, which returns paths only.

Example: vault_search_by_folder({ folder: "Projects" }) or vault_search_by_folder({ folder: "About Me", recursive: false })

When to use: Exploring a folder's contents with full context for vault orientation. Prefer vault_list_notes when you only need paths. Prefer vault_search when you have a text query. Use vault_get_backlinks or vault_get_outgoing_links to explore how notes in a folder connect to the rest of the vault.

Parameters:

  • folder is matched as a path prefix; pass it without a trailing slash ("Projects").

  • recursive (default true) includes all nested subfolders; set false to list only the folder's top level.

  • limit (default 20) caps results.

Errors:

  • An empty or nonexistent folder returns an empty array, not an error.

Returns: JSON array of note metadata (path, title, tags, related, folder, type, created, modified, bytes, leading_callout?, additional_properties), sorted by most recently modified. bytes is the on-disk file size.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax results (default 20)
folderYesFolder path (e.g. "Projects", "About Me")
recursiveNoInclude subfolders (default: true)

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already indicate readOnlyHint, idempotentHint, and non-destructive behavior. The description adds context beyond annotations: sorting by most recently modified, return format as JSON array with specific fields, error behavior (empty array for missing folder), and folder prefix matching. Minor gaps: sorting direction not specified, 'additional_properties' vague.

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?

Well-structured with sections for purpose, example, when-to-use, parameter details, errors, and return format. Front-loaded with purpose. Slightly verbose but each sentence adds value. Could be tightened without losing clarity.

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

Completeness4/5

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

No output schema, so description must explain return values. It lists fields (path, title, tags, etc.) and sorting. Also covers error case (empty array). However, 'additional_properties' is vague and sorting direction is omitted. Still quite complete for a browsing tool.

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

Parameters4/5

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

Schema coverage is 100%, so baseline is 3. The description adds meaning: folder is matched as prefix without trailing slash, recursive defaults to true, limit defaults to 20. It also provides an example call. This is additive and helpful.

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 description clearly states the tool browses notes in a folder with full metadata, distinguishing it from vault_list_notes which returns only paths. The verb 'browse' and resource 'notes in a folder' are specific and actionable.

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?

Provides explicit guidance on when to use this tool (exploring folder contents) and when to prefer alternatives: vault_list_notes for paths, vault_search for text queries, and backlinks/outgoing links for connections. This helps the agent select the correct tool.

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

vault_search_by_propertySearch by PropertyA
Read-onlyIdempotent

Find notes where a frontmatter property matches a value — metadata-only search, no text query needed. Handles both scalar properties (status: "active") and array properties (tags, related): for arrays, matches if any element equals the value (contains check, not exact array match). Matching is exact and case-sensitive; an unknown key or unmatched value returns an empty array, not an error.

Example: vault_search_by_property({ key: "status", value: "in-progress" }) Example: vault_search_by_property({ key: "type", value: "session-log", folder: "Code Projects" })

When to use: Finding notes by metadata when you don't have a text query. Prefer vault_search when you also have a text query (it supports property filters too). Prefer vault_search_by_tag for tag-specific queries (supports hierarchical prefix matching). Use vault_list_property_keys to discover valid keys and vault_list_property_values to see what values a key takes.

Parameters:

  • key + value are both exact and case-sensitive — no partial matching or globbing. All property values are compared as strings, so numeric or boolean properties must be passed as their string representation.

  • For array properties (tags, related), value is tested against each element individually (contains check) — "blog" matches a note with tags: ["blog", "draft"] but not tags: ["my-blog"].

  • folder narrows results to a subtree; omit for vault-wide search. Combined with key+value, this lets you check how a property is used within a specific area.

Returns: JSON array of note metadata (path, title, tags, related, folder, type, created, modified, bytes, leading_callout?, additional_properties), sorted by filesystem mtime descending — recently-synced notes may sort ahead of older content edits.

ParametersJSON Schema
NameRequiredDescriptionDefault
keyYesProperty key name (e.g. "status", "type", "tags"). Use vault_list_property_keys to discover valid keys.
limitNoMax results (default 20). Increase for broad metadata queries.
valueYesValue to match (exact, case-sensitive, e.g. "active", "session-log"). Use vault_list_property_values to discover valid values for a key.
folderNoRestrict to a folder prefix (e.g. "Projects")

TDQS

A4.7/5.0
Behavior4/5

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

Annotations already declare read-only and idempotent. Description adds exact/case-sensitive matching, array contains logic, empty array on no match, and sorting by mtime. No contradictions.

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

Conciseness5/5

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

Well-organized with overview, examples, usage guidance, parameter details, and return value description. No fluff; every sentence earns its place.

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?

Despite no output schema, description fully explains return format, sorting, and edge cases (empty array, numeric strings). Covers all necessary context for agent invocation.

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

Parameters4/5

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

Schema coverage is 100% but description adds value: exact/case-sensitive behavior for key/value, array contains for arrays, folder as subtree filter, and examples. Exceeds baseline.

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?

Clearly states it finds notes by frontmatter property value, distinguishes from full-text search and tag search, and highlights metadata-only nature.

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?

Explicitly specifies when to use (when no text query), and lists alternatives: vault_search for text queries, vault_search_by_tag for tags, and related discovery tools.

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

vault_search_by_tagSearch by TagA
Read-onlyIdempotent

Find notes with a specific tag. By default uses hierarchical prefix matching — a parent tag matches all children (e.g. "project" matches "project/vault-cortex", "project/blog"). Set exact=true for exact match only.

Example: vault_search_by_tag({ tag: "project" }) returns all notes tagged project or project/*.

When to use: Exploring tag hierarchies or finding all notes with a specific tag, without needing a text query. Prefer vault_search when you also need text-based relevance ranking. Use vault_list_tags first to discover available tags.

Parameters:

  • tag is the bare tag name without a leading "#" ("project", not "#project"). Hierarchical tags use "/" separators ("project/vault-cortex").

  • tag + exact interact: with exact=false (default), "project" matches "project", "project/vault-cortex", "project/blog" — the match is prefix-based on the "/" separator, so "project" does NOT match "my-project" or "projects". Set exact=true to match only the literal tag, excluding children.

Errors:

  • An unknown tag or no matches returns an empty array, not an error — don't use as an existence check.

Returns: JSON array of up to 20 notes' metadata (path, title, tags, related, folder, type, created, modified, bytes, leading_callout?, additional_properties), sorted by most recently modified. bytes is the on-disk file size. Promoted keys are in top-level fields; additional_properties contains only unpromoted keys.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagYesTag name without "#" prefix (e.g. "project", "session-log"). Hierarchical tags use "/" separators (e.g. "project/vault-cortex").
exactNoExact match only (default: false, prefix match)

TDQS

A5/5.0
Behavior5/5

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

Annotations already indicate read-only, idempotent, non-destructive. Description adds key behaviors: hierarchical prefix matching, empty array for unknown tags (not an error), return structure, sorted by modified date. No contradictions.

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

Conciseness5/5

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

Well-structured with examples, usage guidelines, parameter details, error handling, and return format. Every sentence adds value; not verbose.

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?

No output schema, but description provides detailed return metadata (path, title, tags, etc.), sorting, and explanation of bytes and additional_properties. Covers error case (empty array). Sufficient for a two-parameter tool.

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%, but description adds significant value: explains no '#' prefix, '/' separators, interaction between tag and exact, exact vs. prefix matching behavior, and that prefix matching is based on '/' separator, not string prefix.

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?

Clearly states 'Find notes with a specific tag.' Distinguishes from siblings vault_search (text ranking) and vault_list_tags (discover tags). Includes examples demonstrating usage.

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?

Explicitly states when to use ('exploring tag hierarchies') and when not to use ('prefer vault_search when text ranking needed', 'use vault_list_tags to discover tags'). Also explains default vs. exact matching.

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

vault_update_memoryUpdate MemoryA
Idempotent

Append a dated entry to a section of a About Me/ memory file. The server prefixes the date automatically ("- YYYY-MM-DD: entry text") and inserts newest-first by default. Idempotent — an exact duplicate (same date + text in the same section) is a no-op, so retrying a timed-out call is safe. Memory files are append-only by default: when a preference changes, append the new state (newest wins) rather than deleting the old one. A file may declare entry-policy: living in frontmatter (surfaced by vault_list_memory_files) — a current-state file where pruning expired entries is expected maintenance rather than a violation.

Example: vault_update_memory({ file: "Opinions", section: "Code patterns (newest first)", entry: "Prefer immutable data structures" })

When to use: Recording a new preference, principle, opinion, or fact about the user. Call vault_list_memory_files first and reuse existing file and section names so entries stay grouped. Prefer vault_write_note for creating non-memory notes. A missing file or section is created automatically (new sections get "(newest first)" appended; new files get a placeholder scope callout to fill in via vault_replace_in_note). A new section name that is nearly identical to an existing heading (an HTML-entity slip, typo, or spacing variation) is rejected instead of created, so a mistyped name cannot silently fragment the file — names differing only in digits (e.g. "2025" vs "2026") are treated as distinct.

Parameters:

  • options.date — ISO YYYY-MM-DD, defaults to today (server timezone).

  • options.position — "top" (default, newest-first) inserts above existing entries; "bottom" appends below them.

Obsidian syntax: Entry text is Obsidian Flavored Markdown. Watch for: #word = tag, [[ = wikilink. Escape with # or backticks when unintentional.

Errors:

  • "refusing memory write: … would shrink content" — safety guard for diverged on-disk content. Re-read with vault_get_memory before retrying.

  • "entry must be a single line" — memory entries are single dated bullets; collapse newlines or append multiple entries.

  • "section must be a single line" — section names become H2 headings; remove line breaks.

  • "date must be a real ISO calendar date" — options.date only accepts an existing calendar date in bare YYYY-MM-DD form (e.g. "2026-07-02"), not a timestamp.

  • "entry/section contains a control character" — entry or section includes a non-printable control byte; remove it before writing.

  • "memory file must not start with a dot" — a dot-prefixed name would create a hidden file (invisible in Obsidian and to every listing); choose a visible name.

  • "section not created: … is nearly identical to existing section …" — near-duplicate guard; pass the exact existing heading (listed in the error) to append there, or choose a clearly different name for a genuinely new section.

Returns: Confirmation message (notes when an identical entry already existed and nothing was written).

ParametersJSON Schema
NameRequiredDescriptionDefault
fileYesMemory file name without .md (e.g. "Principles")
entryYesRaw entry text — a single line (newlines are rejected); the server prepends "- **YYYY-MM-DD**: " automatically. Do not include the date or bullet prefix.
optionsNoOptional date and position overrides
sectionYesH2 section heading (e.g. "Decision heuristics (newest first)"). Matched case-insensitively, with or without the "(newest first)" suffix.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already set idempotentHint=true, and the description goes well beyond this by explaining the date prefixing, newest-first insertion, idempotency details, append-only convention, living policy, and near-duplicate section guard. It fully discloses behavioral traits without contradicting 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 comprehensive but somewhat lengthy. It front-loads key behavior (date prefix, idempotency, append-only), and the example, when-to-use, and error list are well-structured. A bit verbose in spots (e.g., the near-duplicate guard explanation could be tighter), but overall earned its space.

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?

Despite no output schema, the description documents the return value (confirmation message). It covers parameter semantics, error conditions with corrective guidance, and integrates context from sibling tools (vault_list_memory_files, vault_get_memory, vault_write_note). A complete and self-contained specification.

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

Parameters4/5

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

Schema coverage is 100%, so baseline is 3. The description adds value by explaining the default date behavior, position semantics, and the nuance that the date prefix is automatically added. It also clarifies the section matching logic (case-insensitive). Loses a point for not detailing the options.date format more precisely than 'defaults to today' (the error section later covers date format, but the parameter description itself is terse).

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 description clearly states the tool appends a dated entry to a memory file section, which is a specific verb+resource combination. It distinguishes itself from siblings like vault_write_note and vault_get_memory, and the example makes the usage concrete.

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?

The description explicitly says 'When to use: Recording a new preference, principle, opinion, or fact about the user' and advises calling vault_list_memory_files first. It also tells when NOT to use it ('Prefer vault_write_note for creating non-memory notes'), providing clear guidance.

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

vault_update_propertiesUpdate PropertiesA
DestructiveIdempotent

Update a note's frontmatter properties via shallow merge — new keys added, matching keys overwritten, null deletes a key, unmentioned keys preserved. Body is never modified.

Example: vault_update_properties({ path: "Projects/todo.md", properties: { status: "active", draft: null } })

When to use: Changing tags, status, type, or any property without reading/rewriting the full note body. Prefer vault_write_note when creating a new note, or replacing the body (with overwrite: true). Read current properties first with vault_read_note({ properties_only: true }) — arrays are replaced entirely, not appended to.

Errors:

  • "note not found" — path does not exist; create the note first with vault_write_note

  • "path traversal blocked" — path escapes vault root

  • "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

Obsidian syntax: Use arrays for multi-value fields (tags: [a, b]), quote wikilinks ("[[Note]]"), keep types consistent (mismatches cause silent query failures).

Returns: Confirmation message.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesVault-relative path to the note, including the ".md" extension
propertiesYesProperties to merge. New keys are added; existing keys are overwritten; a null value deletes that key; unmentioned keys are preserved.

TDQS

A4.8/5.0
Behavior5/5

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

The annotations already indicate readOnlyHint=false, destructiveHint=true (modification), and idempotentHint=true. The description adds critical behavioral details: the return is a confirmation message (not the updated note), errors list includes 'not found', 'path traversal blocked', 'hidden path blocked', and 'concurrent write in progress' with recovery advice. It also warns that arrays are replaced entirely and that property type mismatches cause silent query failures. This goes well beyond the 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 well-structured with clear sections: operation semantics, example, when-to-use (with alternatives), error handling, and Obsidian syntax. It is informative but slightly long; some error details could be condensed. However, every sentence adds value, and the front-loading of the core operation is effective.

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 the tool has 2 parameters (both required, no enums), no output schema, and annotations providing some but not exhaustive behavioral cues, the description covers all essential aspects: operation semantics, usage with examples, error conditions with handling advice, and Obsidian-specific formatting rules. No critical gaps remain for an agent to invoke this tool correctly.

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

Parameters4/5

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

Schema description coverage is 100%, so the schema already documents both parameters. The description adds an example showing exact syntax for properties (including null deletion and arrays), lists Obsidian-specific conventions (use arrays for multi-value fields, quote wikilinks, keep types consistent), and notes that properties property uses shallow merge. This provides meaningful context beyond the schema's property descriptions.

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 description clearly states the tool updates a note's frontmatter properties via shallow merge, explaining the exact semantics (new keys added, matching keys overwritten, null deletes, unmentioned keys preserved). It also specifies that the body is never modified, which distinguishes it from sibling tools like vault_replace_in_note or vault_write_note.

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?

The description explicitly says when to use this tool (changing tags, status, type, or any property without reading/rewriting the full note body) and also specifies alternatives: pref er vault_write_note when creating a new note or replacing the body, and read current properties first with vault_read_note for arrays (since they are replaced entirely). This provides clear guidance on tool selection.

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

vault_update_taskUpdate TaskA
Destructive

Update a task's status, priority, description, dates, dependencies, block_id, checklist items, or heading placement in one call. Any combination of these can change together — every field passed is written in a single edit.

Example: vault_update_task({ path: "TASKS.md", block_id: "my-task", status: "done" }) — complete a task; on a Kanban board, auto-moves to the done lane Example: vault_update_task({ path: "TASKS.md", block_id: "my-task", heading: "Done" }) — move a task to a different heading (lands at the top of the lane by default) Example: vault_update_task({ path: "TASKS.md", block_id: "my-task", heading: "Done", position: "bottom" }) — move to the bottom of the lane Example: vault_update_task({ path: "TASKS.md", block_id: "my-task", description: "Updated task name", due: "2026-10-01" }) — change description and set due date Example: vault_update_task({ path: "TASKS.md", block_id: "my-task", due: null }) — clear a date field Example: vault_update_task({ path: "TASKS.md", block_id: "my-task", status: "in_progress", add_subtasks: ["Design", "Implement", "Test"] }) — start working and add checklist stages Example: vault_update_task({ path: "TASKS.md", line: 42, assign_block_id: "my-task" }) — add a block_id to a task that lacks one Example: vault_update_task({ path: "TASKS.md", block_id: "my-task", task_id: "abc123" }) — set a Tasks plugin 🆔 identifier

When to use: Any change to an existing task — completing, starting, re-prioritizing, editing text, setting or clearing dates, adding checklist items, assigning block_ids, or moving between headings. Use vault_list_tasks first to get identification fields (path + block_id or line). For creating a new task, use vault_create_task instead.

Parameters:

  • path (required): vault-relative path to the note (must end in ".md").

  • Exactly one of block_id or line is required to identify the task.

  • At least one change is required. Every field passed is applied in the same single write:

    • status: "todo" | "in_progress" | "done" | "cancelled". Manages checkbox and done/cancelled dates. On a Kanban board, "done" moves the card to the done lane together with its checklist sub-items (their checkboxes are left as they are); a sub-task marked done stays under its parent.

    • priority: "highest" | "high" | "medium" | "low" | "lowest" sets the signifier; null removes it.

    • description: replaces the task text. Metadata fields and block_id are preserved.

    • due / scheduled / start / created: YYYY-MM-DD sets the date; null clears it.

    • task_id: string sets the Tasks plugin 🆔; null clears it.

    • depends_on: non-empty string array sets the Tasks plugin ⛔; null clears it.

    • add_subtasks: non-empty string array — appends one indented [ ] checklist item per entry under the task; existing checklist items are kept. For full sub-tasks with their own metadata, use vault_create_task with parent_block_id.

    • assign_block_id: adds or replaces the ^block-id on the task line. Letters, digits, and hyphens only; must be unique within the note.

    • heading: target heading to move the task to. On Kanban boards this is a lane move; works on any note with headings. Not valid on sub-tasks.

    • position: "top" or "bottom" — where within the target heading the task lands after a heading move or auto-done-lane move. Defaults to "top" (first position in the lane). Ignored when no heading move occurs.

    • Clearing is always explicit null — omitting a field leaves it untouched.

  • format: "emoji" or "dataview" — overrides the auto-detected Tasks plugin format.

Errors:

  • "note not found" — path does not exist

  • "exactly one of blockId or line is required" / "blockId and line are mutually exclusive" — pass exactly one of block_id or line

  • "blockId ... not found" — no task line in the note ends with ^block_id

  • "no task at line N" — line doesn't contain a task checkbox

  • "at least one mutation" — no change params provided

  • "cannot move a sub-task to a heading" — explicit heading on a task nested under another task (depth > 0 in vault_list_tasks)

  • "heading "X" not found; available: ..." — target heading doesn't exist; the error lists the note's headings

  • "multiple done lanes detected" — status "done" on a Kanban board with more than one Complete-marked lane; pass heading to pick the lane

  • "no done lane detected" — status "done" on a Kanban board with no Complete marker and no "Done" heading; pass heading explicitly

  • "blockId ... already exists" / "blockId ... contains invalid characters" — assign_block_id must be unique in the note and match [a-zA-Z0-9-]+

  • "invalid date" — a date param fails calendar validation

  • "description cannot be empty" / "dependsOn cannot be empty" / "addSubtasks cannot be empty" / "addSubtasks cannot contain an empty item" — whitespace-only text or an empty array (use null to clear depends_on)

  • "description must be a single line" / "addSubtasks items must be a single line" — a task is one file line; a line break in the text would split its metadata onto a line the parser never reads

  • "taskId ... contains invalid characters" / "dependsOn entry ... contains invalid characters" — task_id and every depends_on entry must match [a-zA-Z0-9_-]+ (the Tasks plugin's id grammar)

  • "concurrent write in progress" — another write to this note is in flight; retry

Returns: JSON { path, line, description, block_id, heading, subtasks, changes } — line is the final 1-based position; description is the current text; block_id and heading reflect the task after the update (block_id is omitted when the task has none, heading when the task sits above the first heading); subtasks lists each checklist item added by add_subtasks as { line, description } (omitted when none were added) — checklist items carry no block_id, so line is the handle for a follow-up update; changes lists every field applied as "field: before → after", with "(none)" for an absent value (for subtasks the two sides are checklist-item counts).

ParametersJSON Schema
NameRequiredDescriptionDefault
dueNoDue date (YYYY-MM-DD) to set, or null to clear.
lineNo1-based line number from vault_list_tasks. Fragile if the file changed since the query.
pathYesVault-relative path to the note containing the task (must end in ".md")
startNoStart date (YYYY-MM-DD) to set, or null to clear.
formatNoField format for new metadata. Default: auto-detected from .obsidian/ config, falling back to emoji.
statusNoTarget status. "done" appends the ✅ date and, on a Kanban board, moves the card and its checklist sub-items to the done lane (sub-item checkboxes are left as they are). "cancelled" appends the ❌ date.
createdNoCreated date (YYYY-MM-DD) to set or clear. Typically auto-stamped; use for corrections.
headingNoTarget heading to move the task to. On Kanban boards this is a lane move; works on any note with headings. Not valid on sub-tasks.
task_idNoTasks plugin 🆔 identifier to set, or null to clear.
block_idNoStable task identifier — the ^block-id at the end of the task line, without the ^. Preferred over line.
positionNoWhere within the target heading the task lands after a heading move or auto-done-lane move. Defaults to "top". Ignored when no heading move occurs.
priorityNoPriority signifier to set, or null to remove it.
scheduledNoScheduled date (YYYY-MM-DD) to set, or null to clear.
depends_onNoTasks plugin ⛔ dependency IDs to set (non-empty), or null to clear.
descriptionNoNew task description text. Replaces the existing description; metadata fields and block_id are preserved.
add_subtasksNoChecklist items to append, one indented [ ] line each, under the task's existing items — never replaces them. Can be combined with any other change. For full sub-tasks with metadata, use vault_create_task with parent_block_id.
assign_block_idNoAdd or replace the ^block-id on the task line. Letters, digits, and hyphens only; must be unique within the note.

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already mark this as a destructive, non-idempotent write, and the description adds substantial behavioral context: single-write atomicity, explicit-null clearing semantics, Kanban lane auto-moves, sub-task restrictions, position defaults, and a full catalog of error conditions. None of this contradicts the annotations; it complements them richly.

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 well-structured and front-loaded with a summary and examples, followed by usage rules, parameter semantics, errors, and returns. It is long, but justified given 17 parameters and a complex mutation surface. It loses one point because the parameter block partly restates schema descriptions, adding some redundancy despite the valuable extra rules woven in.

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?

With 17 parameters, no output schema, and a destructive mutation tool, the description is exceptionally complete: it covers prerequisites, identification strategies, per-field behavior, error handling, and the exact return payload. An agent has everything needed to select and invoke this tool correctly.

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?

Even though schema coverage is 100%, the description adds meaning beyond the schema: exactly one of block_id or line must be provided, at least one mutation is required, omitted fields remain untouched, null clears fields, assign_block_id has uniqueness and character constraints, and add_subtasks appends without replacing existing checklist items. The examples further illustrate valid combinations and expected behavior.

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 description opens with a specific verb and resource scope: updating status, priority, description, dates, dependencies, block_id, checklist items, or heading placement in one call. It clearly names the operation's boundaries and distinguishes itself from vault_create_task, which is listed as a sibling. This is far from a tautology and gives an agent a precise mental model.

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?

An explicit 'When to use' block states that this tool is for any change to an existing task, directs the agent to vault_list_tasks first to obtain identification fields, and explicitly routes new-task creation to vault_create_task instead. This is unambiguous guidance with a named alternative.

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

vault_write_noteWrite NoteA
Destructive

Create a markdown note. Errors if a note already exists at the path unless overwrite is set. Body replaces the entire note content — this is a full write, not a partial edit. Properties are passed separately and merged with any existing properties when overwriting (new keys added, matching keys overwritten, keys set to null removed, unmentioned keys preserved).

Example: vault_write_note({ path: "Projects/notes.md", body: "# Notes\n\nProject notes here.", properties: { tags: ["project"], type: "project" } }) Example: vault_write_note({ path: "Projects/notes.md", body: "Updated content.", overwrite: true })

When to use: Creating a new note. Set overwrite: true only when you intend to replace an existing note's body. Prefer vault_update_properties for property-only edits (no body round-trip). Prefer vault_update_memory for appending dated entries to About Me/ memory files.

Limitation: Writes the entire body. Do not use for surgical edits to large files — existing content will be lost unless you include it in the body parameter.

Errors:

  • "note already exists" — a note already lives at this path; set overwrite: true to replace it, or use vault_patch_note / vault_replace_in_note for partial edits

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

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

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

Obsidian syntax: Body is Obsidian Flavored Markdown (no escaping applied). Watch for: #word = tag (escape with #), [[ = wikilink, %% = comment block. In properties: quote wikilink values ("[[Note]]"), use YAML lists for tags, keep property types consistent (string/number/list mismatches cause silent query failures).

Returns: Confirmation message.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyYesMarkdown body content — do not include frontmatter fences (---); use the properties parameter instead.
pathYesVault-relative path including the ".md" extension (e.g. "Projects/notes.md"). Parent folders are created as needed.
overwriteNoAllow overwriting an existing note (default: false — errors if file exists).
propertiesNoOptional properties to merge. New keys are added; existing keys with matching names are overwritten; a null value deletes that key; unmentioned keys are preserved from the existing file.

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already mark destructiveHint: true, but description adds extensive context: full write behavior, property merge semantics, lack of partial editing, and detailed error conditions (note exists, hidden path, concurrent write, control characters). No contradiction with 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 well-structured with clear sections (body, use cases, limitations, errors, Obsidian syntax). It is slightly verbose due to examples and detailed error list, but every paragraph earns its place. Could trim the examples slightly but still effective.

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 no output schema, the description provides a confirmation message return. It covers all four parameters, error conditions, behavioral nuances, and integration with Obsidian syntax. For a write tool with destructive potential, it is complete.

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%, so baseline is 3. However, description adds significant value: clarifies body replaces entire content, properties merge with existing, and provides YAML-specific details (escape tags, quote wikilinks, consistent types). These go well beyond the schema's short descriptions.

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 description clearly states the tool creates a markdown note and distinguishes it from siblings by explicitly naming alternatives like vault_update_properties and vault_update_memory. The verb 'create' plus resource 'markdown note' is specific.

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?

Provides explicit when-to-use guidance: creating a new note, only set overwrite when replacing. Lists specific alternatives for property-only edits and memory appends. Also warns about limitations for surgical edits.

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. Dates show when Glama detected each change.

  1. 7 tool updatesv0.41.2
    • Addedvault_create_task
    • Changedvault_delete_span2 fields changed
      • changedInput schema / properties / end_anchor / description
        Previous value: -"Short, unique substring on the LAST line of the block, searched at or after the start_anchor line. Omit to delete just the single line containing start_anchor."New value: +"Short, unique substring that identifies the LAST line of the block, searched at or after the start_anchor line. The entire line is selected. Omit to delete just the single line containing start_anchor."
      • changedInput schema / properties / start_anchor / description
        Previous value: -"Short, unique substring on the first line of the block to delete (case-sensitive). Pick a brief fragment — do not paste the whole block."New value: +"Short, unique substring that identifies the first line of the block (case-sensitive). The entire line is selected, not just the substring. Pick a brief fragment — do not paste the whole block."
    • Addedvault_insert_at_anchor
    • Changedvault_list_tasks5 fields changed
      • changedInput schema / properties / limit / description
        Previous value: -"Max results (default 50)"New value: +"Max results (default 50); total always reports the full match count"
      • addedInput schema / properties / limit / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / limit / minimum
        Added value: +1
      • changedInput schema / properties / limit / type
        Previous value: -"number"New value: +"integer"
      • addedInput schema / properties / top_level_only
        Added value: +{
        +  "description": "When true, only top-level tasks (depth 0) are returned — excludes indented sub-tasks and checklist items. Default false.",
        +  "type": "boolean"
        +}
    • Changedvault_patch_note1 field changed
      • 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)."
    • Addedvault_replace_span
    • Changedvault_update_task18 fields changed
      • addedInput schema / properties / add_subtasks
        Added value: +{
        +  "description": "Checklist items to append, one indented [ ] line each, under the task's existing items — never replaces them. Can be combined with any other change. For full sub-tasks with metadata, use vault_create_task with parent_block_id.",
        +  "items": {
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "minItems": 1,
        +  "type": "array"
        +}
      • addedInput schema / properties / assign_block_id
        Added value: +{
        +  "description": "Add or replace the ^block-id on the task line. Letters, digits, and hyphens only; must be unique within the note.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / created
        Added value: +{
        +  "anyOf": [
        +    {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Created date (YYYY-MM-DD) to set or clear. Typically auto-stamped; use for corrections."
        +}
      • addedInput schema / properties / depends_on
        Added value: +{
        +  "anyOf": [
        +    {
        +      "items": {
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "minItems": 1,
        +      "type": "array"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Tasks plugin ⛔ dependency IDs to set (non-empty), or null to clear."
        +}
      • addedInput schema / properties / description
        Added value: +{
        +  "description": "New task description text. Replaces the existing description; metadata fields and block_id are preserved.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / due
        Added value: +{
        +  "anyOf": [
        +    {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Due date (YYYY-MM-DD) to set, or null to clear."
        +}
      • changedInput schema / properties / format / description
        Previous value: -"Field format for new metadata (done dates, priority). Overrides the auto-detected Tasks plugin config. Default: auto-detected from .obsidian/ config, falling back to emoji."New value: +"Field format for new metadata. Default: auto-detected from .obsidian/ config, falling back to emoji."
      • addedInput schema / properties / heading
        Added value: +{
        +  "description": "Target heading to move the task to. On Kanban boards this is a lane move; works on any note with headings. Not valid on sub-tasks.",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • removedInput schema / properties / lane
        Removed value: -{
        -  "description": "Target Kanban lane heading for a lane move. Only valid on Kanban boards.",
        -  "minLength": 1,
        -  "type": "string"
        -}
      • addedInput schema / properties / position
        Added value: +{
        +  "description": "Where within the target heading the task lands after a heading move or auto-done-lane move. Defaults to \"top\". Ignored when no heading move occurs.",
        +  "enum": [
        +    "top",
        +    "bottom"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / priority / anyOf
        Added value: +[
        +  {
        +    "enum": [
        +      "highest",
        +      "high",
        +      "medium",
        +      "low",
        +      "lowest"
        +    ],
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / priority / description
        Previous value: -"Target priority. \"none\" removes the priority emoji."New value: +"Priority signifier to set, or null to remove it."
      • removedInput schema / properties / priority / enum
        Removed value: -[
        -  "highest",
        -  "high",
        -  "medium",
        -  "low",
        -  "lowest",
        -  "none"
        -]
      • removedInput schema / properties / priority / type
        Removed value: -"string"
      • addedInput schema / properties / scheduled
        Added value: +{
        +  "anyOf": [
        +    {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Scheduled date (YYYY-MM-DD) to set, or null to clear."
        +}
      • addedInput schema / properties / start
        Added value: +{
        +  "anyOf": [
        +    {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Start date (YYYY-MM-DD) to set, or null to clear."
        +}
      • changedInput schema / properties / status / description
        Previous value: -"Target status. \"done\" appends ✅ date and auto-moves to done lane on Kanban boards. \"cancelled\" appends ❌ date."New value: +"Target status. \"done\" appends the ✅ date and, on a Kanban board, moves the card and its checklist sub-items to the done lane (sub-item checkboxes are left as they are). \"cancelled\" appends the ❌ date."
      • addedInput schema / properties / task_id
        Added value: +{
        +  "anyOf": [
        +    {
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Tasks plugin 🆔 identifier to set, or null to clear."
        +}
  2. 1 tool updatev0.37.1
    • Changedvault_patch_note1 field changed
      • 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. 3 tool updatesv0.36.0
    • Changedvault_get_backlinks1 field changed
      • changedInput schema / properties / path / description
        Previous value: -"Exact vault-relative path including .md extension (e.g. \"Projects/vault-cortex.md\"). Case-sensitive."New value: +"Exact vault-relative path including .md or .canvas extension (e.g. \"Projects/vault-cortex.md\"). Case-sensitive."
    • Changedvault_get_outgoing_links1 field changed
      • changedInput schema / properties / path / description
        Previous value: -"Exact vault-relative path including .md extension (e.g. \"Projects/vault-cortex.md\"). Case-sensitive."New value: +"Exact vault-relative path including .md or .canvas extension (e.g. \"Projects/vault-cortex.md\"). Case-sensitive."
    • Changedvault_read_note2 fields changed
      • addedInput schema / properties / limit
        Added value: +{
        +  "description": "Maximum lines returned (default: all remaining). A paged read's metadata line states the window, the total line count, and the next start_line.",
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / start_line
        Added value: +{
        +  "description": "First line to return, 1-based (default 1). Pages the delivered rendition (full body or a heading section). Not valid for outline or properties_only (JSON modes).",
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
  4. 1 tool updatev0.34.0
    • Changedvault_read_file2 fields changed
      • addedInput schema / properties / limit
        Added value: +{
        +  "description": "Maximum lines returned (default: all remaining). A paged read's metadata line states the window, the total line count, and the next start_line. The output byte cap still applies to the window — reduce limit if it overflows.",
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / start_line
        Added value: +{
        +  "description": "First line to return, 1-based (default 1). Pages any text result — text formats, canvas outlines and raw JSON, PDF-extracted text. Not valid for images or for PDFs with raw: true.",
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
  5. 18 tool updatesv0.32.1
    • Addedvault_delete_span
    • Addedvault_get_memory
    • Addedvault_get_outgoing_links
    • Addedvault_list_memory_files
    • Addedvault_list_notes
    • Addedvault_list_property_keys
    • Addedvault_list_property_values
    • Addedvault_list_tags
    • Addedvault_memory_recall
    • Addedvault_move_note
    • Addedvault_read_note
    • Addedvault_recent_notes
    • Addedvault_replace_in_note
    • Addedvault_search_by_folder
    • Addedvault_search_by_property
    • Addedvault_update_properties
    • Addedvault_update_task
    • Addedvault_write_note
  6. 20 tool updatesv0.32.0
    • Removedvault_delete_span
    • Removedvault_get_memory
    • Removedvault_get_outgoing_links
    • Addedvault_list_files
    • Removedvault_list_memory_files
    • Removedvault_list_notes
    • Removedvault_list_property_keys
    • Removedvault_list_property_values
    • Removedvault_list_tags
    • Removedvault_memory_recall
    • Removedvault_move_note
    • Addedvault_read_file
    • Removedvault_read_note
    • Removedvault_recent_notes
    • Removedvault_replace_in_note
    • Removedvault_search_by_folder
    • Removedvault_search_by_property
    • Removedvault_update_properties
    • Removedvault_update_task
    • Removedvault_write_note

TDQS

A4.4/5.0
Disambiguation4/5

Most tools have clearly distinct purposes (e.g., read vs write vs delete vs search), but the large set of discovery/search tools (vault_search, vault_search_by_tag, vault_search_by_folder, vault_search_by_property, vault_list_tags, vault_list_property_keys, etc.) have overlapping roles that could confuse an agent. The descriptions are thorough, but the sheer number of similar-purpose tools reduces clarity.

Naming Consistency4/5

The naming follows a consistent 'vault_verb_noun' pattern, with verbs like read, write, delete, move, search, list, get, update. Minor inconsistency: some compound verbs use 'by' (search_by_tag, search_by_folder) while others do not (list_tags, get_backlinks). Also 'delete_span' vs 'delete_note' vs 'delete_memory' is slightly irregular but still readable.

Tool Count4/5

30 tools is on the high side for a vault server, but each tool addresses a distinct operation (CRUD for notes, properties, memory, tasks, files, links, search, browsing). The scope is broad enough to justify the count; a few tools could be merged (e.g., search_by_tag and search_by_folder into a more flexible search), but overall the count is reasonable.

Completeness4/5

The tool surface covers CRUD for notes, properties, memory, tasks, and files, plus extensive search/link discovery. Minor gaps: no tool to create a non-markdown file (only read), no explicit folder creation, and no tool to create a daily note (though vault_write_note can). The memory and task subsystems are well-integrated. Overall, few dead ends.

Maintenance

ActivityActive
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    A server that enables AI agents to perform sophisticated knowledge discovery and analysis across Obsidian vaults through the Local REST API plugin, supporting complex multi-step workflows with advanced filtering and full content retrieval.
    3
    21
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    A third-party MCP server for interacting with HashiCorp Vault to manage ACL policies, audit devices, and secret engines like KV v2, PKI, and Transit. It provides tools for system backend administration and includes prompts for generating security policy configurations.
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aliasunder/vault-cortex'

If you have feedback or need assistance with the MCP directory API, please join our Discord server