Я веду Obsidian как доску со стикерами: набрасываю идеи, фиксирую мысли на ходу, собираю технические заметки и черновики. Claude Code использую как думалку: разбираю архитектуру, пишу код, обсуждаю решения и иногда прошу превратить хаос в нормальный план.

Проблема в том, что они жили в параллельных мирах. Claude не видел мои заметки, и каждый раз, когда мне нужен был контекст, приходилось вручную копировать куски из Obsidian. Это долго, неудобно, а по дороге легко забыть важную деталь или скормить ассистенту не тот фрагмент.

Конечно, для Obsidian уже существуют готовые MCP-серверы. MCP (Model Context Protocol) — это стандарт, через который AI-клиент может вызывать внешние инструменты. Например, искать файлы, читать документы, создавать записи, ходить в базы и так далее. Но большинство готовых решений для Obsidian работают с локальными файлами, а значит, vault должен лежать рядом с агентом на той же машине.

Мне же хотелось, чтобы заметки синхронизировались между устройствами, AI-агент был доступен из разных клиентов, всё self-hosted, без облачной подписки на синхронизацию и запущенного Obsidian Desktop на сервере.

В итоге получился remote MCP-сервер, который ходит напрямую в CouchDB, где уже лежат данные Obsidian LiveSync. Сейчас проект даёт AI-клиентам 20 инструментов для работы с vault: поиск, чтение, создание и обновление заметок, теги, свойства, граф связей, canvas, шаблоны. Первым клиентом был Claude, потом добавился Codex. Но путь туда оказался не совсем прямым. Пришлось разобраться с форматом LiveSync, OAuth 2.1, bearer-токенами и багом, который однажды тихо удалил куски заметки.

Шаг первый: домашний сервер и CouchDB

У меня дома стоит небольшой сервер на Ubuntu. Роутер Keenetic с KeenDNS даёт внешний домен, SSH уже был настроен, поэтому туда всё и поехало.

Для синхронизации Obsidian я выбрал Self-hosted LiveSync. Это community-плагин, который хранит vault в CouchDB. Это не просто «ещё один бэкап». Все клиенты Obsidian подключаются к одной базе, а LiveSync синхронизирует изменения между ними.

Работает это так: плагин стоит на десктопе и телефоне, оба подключены к CouchDB. Когда заметка меняется, LiveSync разбивает данные на части, отправляет изменившиеся документы в базу, а остальные устройства получают обновление. Для пользователя это выглядит как обычная синхронизация, но под капотом Obsidian-файл превращается в набор документов CouchDB.

CouchDB здесь удобна тем, что у неё есть HTTP API и репликация из коробки. Своя база, полный контроль и никаких внешних сервисов.

CouchDB я поставил нативно, без Docker. На домашнем железе лишний слой контейнеров мне был не нужен. Просто запустил его через systemd на порту 5443.

Первая неожиданность — CORS и KeenDNS

LiveSync на десктопе подключился без проблем, а вот мобильные клиенты Obsidian с LiveSync в моей конфигурации не заработали без HTTPS. Я не буду притворяться, что докопался до единственной канонической причины. На практике мобильный клиент требовал HTTPS, а в моей конфигурации KeenDNS при проксировании молча срезал CORS-заголовки. Браузер видел ответ без нужных заголовков и блокировал запрос.

Решение вышло несимметричным, но рабочим: десктоп синхронизируется напрямую по HTTP, мобильные клиенты ходят через отдельный KeenDNS-поддомен, а MCP-сервер на домашнем сервере обращается к той же CouchDB напрямую.

Схематично получилось так:

Obsidian Desktop  -- HTTP ------------┐
                      │
Obsidian Mobile   -- HTTPS -- KeenDNS -- CouchDB
                      │
MCP-сервер        -- HTTP ------------┘

На этом этапе AI ещё ни при чём. Просто Obsidian уже синхронизируется через CouchDB, и у меня появляется база, к которой можно обратиться с сервера.

Шаг второй: MCP-сервер поверх CouchDB

Когда LiveSync заработал, мне пришла следующая мысль. Раз Obsidian уже хранит все заметки в CouchDB, почему бы не дать к ним прямой доступ Claude? Без Local REST API-плагина. Без запущенного Obsidian Desktop на сервере. Без копирования локального vault рядом с агентом. Просто HTTP-запросы к CouchDB и MCP-инструменты поверх них.

MCP-сервер в этой схеме — переводчик. Claude, Codex или другой клиент не знают, как устроен LiveSync, где лежат чанки и как из них собрать markdown. Они вызывают человеческие инструменты: search, fetch, update_note, get_links, find_hub_notes. А сервер внутри делает всю грязную работу: идёт в CouchDB, находит документ заметки, читает список чанков, собирает содержимое и возвращает нормальный markdown.

Например, запрос концептуально выглядит так:

fetch("Идеи/проект.md")
  -> найти manifest-документ заметки
  -> прочитать children
  -> загрузить каждый h:chunk
  -> склеить data в правильном порядке
  -> вернуть markdown клиенту

Второй сюрприз — формат хранения LiveSync

LiveSync не хранит заметку как один файл. В CouchDB лежит манифест с массивом children, а сами куски текста лежат отдельными документами с ID вида h:...:

идеи/проект.md -> children: ["h:a1b2c3", "h:d4e5f6"]
h:a1b2c3        -> первая часть текста
h:d4e5f6        -> вторая часть текста

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

Это важная деталь. Позже именно она стала одной из причин бага с потерей разделов.

Поиск в первом релизе я сделал просто: сервер получает список заметок, читает содержимое каждой и ищет текст или regex уже в памяти. Отдельного индекса на тот момент не было. Для небольшого vault этого хватает, но это честное ограничение первого релиза, а не магический full-text search уровня поискового движка.

Шаг третий: OAuth 2.1

Я написал сервер, запустил, пытаюсь подключить Claude.ai — не работает. Лезу в документацию MCP и Claude по custom connectors. Оказывается, remote MCP — это не то же самое, что локальный MCP.

Локальный MCP обычно запускается рядом с клиентом. Он может читать локальный конфиг, переменные окружения, файлы и в целом находится в зоне доверия пользователя. Remote MCP доступен по сети. Claude.ai подключается к нему из облачной инфраструктуры Anthropic, а не с моего компьютера. Значит, сервер должен уметь нормально проверять, кто к нему пришёл.

Для Claude.ai это означает OAuth 2.1: Authorization Code Flow с PKCE. Не API-ключ в заголовке, не Basic Auth, не пароль в конфиге, а полноценный flow с редиректом пользователя, выдачей access-токенов и refresh-токенов.

Пришлось реализовать всё, что сначала казалось избыточным для «просто дать Claude доступ к заметкам»:

  • endpoint авторизации;

  • endpoint выдачи токена;

  • refresh-токенов;

  • хранение кодов авторизации и сессий;

  • pre-registered OAuth client;

  • redirect URI для Claude;

  • проверку токена на MCP-запросах.

В текущей версии OAuth-клиент из коробки рассчитан на Claude.ai и Claude Code. Dynamic Client Registration выключен. Для других OAuth-клиентов нужно либо предрегистрировать отдельные redirect URI, либо включать DCR, понимая риск: любой, кто знает URL сервера, сможет попробовать зарегистрировать клиент.

Полезные ссылки, которые стоит держать рядом:

После настройки OAuth сервер стал подключаться через Claude Connectors. Добавляете URL MCP-сервера в настройках Claude, проходите авторизацию, и vault доступен не только в одном локальном окружении, а на клиентах этого пользователя.

Не только Claude: Bearer-only и Codex

Отдельный поворот случился позже, когда меня забанил Claude. Сразу стало ясно, что привязывать всю базу знаний к одному AI-клиенту — плохая идея. Если сервер действительно полезен, он должен работать не только с Claude.

Так появилась поддержка Codex и более простой режим авторизации — Bearer-only.

OAuth остаётся нужен там, где его требует клиент, например для Claude.ai. Но не каждому клиенту нужен полный Authorization Code Flow. Для локальных и агентских сценариев часто достаточно статического токена: клиент отправляет Authorization: Bearer ..., сервер сравнивает токен с MCP_API_KEY и либо пускает запрос, либо отклоняет.

В конфигурации это выглядит так:

MCP_API_KEY=your_api_key

Если MCP_API_KEY задан, сервер выбирает bearer-режим. Если bearer не задан, но есть OAUTH_PASSWORD, включается OAuth. Если не задано ничего, сервер падает при старте, а не запускается открытым. Это важное поведение: MCP-сервер имеет доступ к заметкам, и случайно поднять его без авторизации было бы плохой идеей.

Для Codex подключение документировано так:

[mcp_servers.obsidian]
url = "https://your-server/mcp"
bearer_token_env_var = "MCP_API_KEY"

То есть в окружении, где работает Codex, лежит тот же MCP_API_KEY, а в конфиге указан remote MCP endpoint. После этого Codex получает те же инструменты vault: может искать заметки, читать контекст, создавать планы, обновлять документы.

Для меня это оказался важный архитектурный вывод: Obsidian должен быть общей базой знаний для разных AI-инструментов, а не расширением одного конкретного клиента.

Что получилось в первом релизе

Первый релиз, 1.0.0, вышел 21 марта 2026 года. В нём было 20 инструментов для работы с vault.

Группа

Инструменты

Заметки

search, fetch, create, update, delete, move, duplicate, list

Метаданные

properties, tags, get_all_tags

Граф

links, link_graph, hub_notes, orphaned_notes

Canvas

node, edge

Прочее

vault_stats, list_templates, create_from_template

Группировка здесь по смыслу, а не по уровню риска. Это важно: search и fetch относительно безопасны, потому что только читают. А вот create, update, delete и move уже меняют базу. Когда AI получает write-инструменты к вашей базе знаний, нужно думать о бэкапах и failure modes заранее.

Вот простой пример работы:

> найди мои заметки,где упоминается CouchDB

Claude: Нашёл 3 заметки:

Инструменты/mcp/obsidian-mcp.md
Технические заметки/MCP Obsidian — проблема с секциями.md
Идеи/Хабр — статья про obsidian-livesync-mcp.md
Показать содержимое?

Но полезность не только в поиске. Например, агента можно попросить найти хабовые заметки, на которые больше всего ссылок и которые сами много куда ссылаются:

> покажи хабовые заметки в vault
MCP: find_hub_notes(min_links=5)
Claude: Вижу несколько центров:
Работа/Идеи/Проект Анализ требований/README.md
Идеи/Хабр — статья про obsidian-livesync-mcp.md
Инструменты/mcp/obsidian-mcp.md

Или найти осиротевшие заметки без входящих и исходящих связей. Для Obsidian это полезно: агент становится не просто редактором файлов, а навигатором по базе знаний.

Но первый релиз был не идеальным. Поиск проходил по заметкам без отдельного индекса. OAuth из коробки был рассчитан на Claude. А write-инструменты оказались рискованнее, чем я думал. И, как выяснилось, ошибка в чтении чанков могла превращаться в потерю данных.

Баг, который съедал заметки

Через неделю реального использования я поймал неприятный баг, когда

попросил Claude обновить один раздел в большом документе примерно на 300 строк через search-replace. Операция прошла, заметка сохранилась, но несколько других разделов исчезли. Никакой ошибки, никакого предупреждения. Данные просто тихо потерялись.

Первой мыслью было: Claude плохо сделал replace. Такое бывает — модель могла заменить не тот фрагмент, переписать больше текста, неаккуратно собрать ответ. Но улики не сходились. Исчезали разделы вне зоны замены: начало, середина и отдельные блоки, к которым запрос вообще не относился.

Потом проявился ещё один странный симптом. При попытке вернуть потерянное через повторный search-replace сервер отвечал «No matches found», хотя визуально строка совпадала с тем, что должно было лежать в файле. Это уже было похоже не на ошибку модели, а на то, что сам сервер видит не тот документ, который вижу я.

Временный обход нашёлся быстро. Я использовал mode=overwrite с полным содержимым документа. Это было медленно и неудобно, зато данные перестали пропадать. Значит, проблема была не в самой CouchDB как базе и не в LiveSync как синхронизации, а в цепочке «прочитал заметку → изменил кусок → записал обратно».

Диагностика показала три уровня проблемы.

Уровень 1 — чтение. read_note_content молча пропускала чанки, если те не находились в CouchDB. Вместо ошибки сервер возвращал частичный контент:

# Было: тихо пропустить битый чанк
for child_id in children:
    chunk = await self.get_doc(child_id)
    if chunk:
        parts.append(chunk["data"])
    # если нет — просто идём дальше, потеряв кусок заметки

Уровень 2 — запись. write_note сначала удаляла старые чанки, потом писала новые. Если операция падала посередине, документ мог остаться без содержимого.

Уровень 3 — обновление. obsidian_update_note читала заметку, делала search-replace в памяти и писала результат обратно. Если чтение возвращало неполный текст, update перезаписывал заметку этим неполным текстом и не понимал, что только что уничтожил часть документа.

Фикс вышел в версии 1.0.1 от 10 апреля 2026 года.

Чтение стало fail-fast:

for child_id in children:
    chunk = await self.get_doc(child_id)
    if chunk is None:
        raise ValueError(
            f"Chunk '{child_id}' not found for document '{doc_id}'. "
            "Document may be corrupted or still syncing."
        )
    data = chunk.get("data", "")
    if not isinstance(data, str):
        raise ValueError(
            f"Chunk '{child_id}' has unexpected data type."
        )
    parts.append(data)

Запись стала безопаснее по порядку операций. Теперь сначала создаётся новый чанк, и только потом удалялись старые.

# Создаём новый чанк первым
chunk_id = self._generate_chunk_id()
await self.put_doc(chunk_id, {
    "_id": chunk_id,
    "data": content,
    "type": "leaf",
})
# Старые чанки удаляем только после успешной записи нового
for child_id in doc["children"]:
    chunk = await self.get_doc(child_id)
    if chunk:
        await self.delete_doc(child_id, chunk["_rev"])

И главное: obsidian_update_note теперь ловит ошибку чтения и возвращает её пользователю, а не записывает неполный документ обратно.

После фикса правило стало простым: если заметку нельзя собрать полностью, её нельзя обновлять. Лучше явная ошибка, чем тихая потеря данных.

Итоговая схема

Сейчас схема выглядит так:

Obsidian Desktop / Mobile
        ↕ LiveSync
      CouchDB
        ↕ HTTP
   MCP-сервер
        ↕ OAuth 2.1 или Bearer token
 Claude.ai / Claude Code / Codex / другие MCP-клиенты

Obsidian продолжает синхронизироваться как раньше. MCP-сервер не требует запущенного Obsidian Desktop и работает напрямую с CouchDB. Claude подключается через OAuth-сценарий. Codex и другие клиенты могут использовать bearer-токен, если им подходит такой режим.

Заметки становятся общей базой знаний для AI-инструментов. Это уже не «папка файлов на одном компьютере», а удалённый vault, к которому можно подключать разных агентов.

Как поднять у себя

Минимально нужно:

  • CouchDB с данными Obsidian LiveSync;

  • Python 3.11+;

  • домен с HTTPS для remote MCP;

  • понимание, какой клиент будете подключать: Claude через OAuth или Codex/другой клиент через bearer-токен.

Общий порядок такой:

  1. Поднять CouchDB.

  2. Создать базу для LiveSync.

  3. Настроить CORS так, чтобы Obsidian LiveSync мог подключаться к CouchDB.

  4. Подключить Self-hosted LiveSync в Obsidian.

  5. Проверить синхронизацию хотя бы на одном-двух устройствах.

  6. Поднять MCP-сервер.

  7. Настроить авторизацию.

  8. Подключить AI-клиент.

Сам сервер:

git clone https://github.com/Selenion/obsidian-livesync-mcp
cd obsidian-livesync-mcp
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
python run.py

В .env сейчас используются такие переменные:

COUCHDB_URL=http://localhost:5984
COUCHDB_USER=admin
COUCHDB_PASSWORD=your_password
COUCHDB_DATABASE=obsidian
MCP_API_KEY=your_api_key
OAUTH_PASSWORD=your_oauth_password
OAUTH_CLIENT_ID=your_client_id
OAUTH_CLIENT_SECRET=your_client_secret
MCP_SERVER_URL=https://your-domain.com
MCP_HOST=0.0.0.0
MCP_PORT=8484

Для Claude.ai нужен OAuth-сценарий: URL сервера добавляется как custom connector, а client ID и client secret берутся из .env.

Для Codex — bearer-режим:

[mcp_servers.obsidian]
url = "https://your-server/mcp"
bearer_token_env_var = "MCP_API_KEY"

Отдельно про безопасность

CouchDB не стоит открывать наружу напрямую. Креды CouchDB — это доступ ко всем заметкам. Наружу лучше выставлять защищённый HTTPS/MCP-слой, а саму базу держать доступной только там, где она действительно нужна.

Перед включением write-инструментов сделайте бэкап vault или CouchDB. Read-инструменты полезны сами по себе, а запись лучше включать только после того, как вы понимаете, как восстановиться при ошибке.

Что дальше

Следующие очевидные направления развития:

  • нормальный индекс или векторный поиск, чтобы не проходить весь vault при каждом поиске;

  • webhooks при изменениях vault;

  • более удобная поддержка разных OAuth-клиентов;

  • отдельные политики для read/write-инструментов;

  • возможно, небольшая админка для диагностики подключения и состояния базы.

Код открыт: https://github.com/Selenion/obsidian-livesync-mcp

Если используете Obsidian LiveSync и хотите подключить к нему AI-агента — попробуйте и напишите в комментариях, как это работает на вашем vault.

P.S. Эту статью я писал вместе с AI-ассистентами. Сначала Claude помогал разрабатывать сервер и ловить баги. Потом, когда Claude меня забанил, Codex помог продолжить работу. В каком-то смысле инструмент действительно описывает сам себя и уже не через одного клиента.

Также можно прочитать статьи о том, как AI-инструменты встраиваются в разработку и работу с данными:

От vibe coding к Spec-Driven Development: как приручить хаос ИИ-разработки
Text2SQL в аналитике: как мы научили ИИ понимать бизнес-запросы без посредников

Комментарии (6)


  1. prdenisov
    23.06.2026 10:14

    класс, спасибо за инфу. Обсидиан юзаю уже года 3,5, наверное, в связке с ИИ крайне интересный комбайн получается


    1. Undesired Автор
      23.06.2026 10:14

      Я от случая к случаю использовал, было неудобно, что нет синхронизации между разными тачками. Потом поставил Livesync и Obsidian стал превращаться уже в рабочий инструмент. А потом осознал, что для ЛЛМ md файлы отлично использовать и как память и как заметки. Решил поэкспериментировать...и вот получился удобный инструмент, который я использую на ежедневной основе.


  1. Vedomir
    23.06.2026 10:14

    Огромное количество смайлов в превьюшке к статье сразу отпугивает и создает впечатление нерослопа. Причем в самой статье их уже нет.


    1. Lezor
      23.06.2026 10:14

      А мне нравится, вёрстка как в телеге, поэтому и зашёл сразу)


  1. apeshand
    23.06.2026 10:14

    Я.Клауд давал пробные 3т.р. рублей на счёт, там создал бакет на 50Гб, установил в obsidian Remotely Save, туда втолкнул креды от бакета и теперь на всех моих устройствах нужные мне заметки.

    За свои заметки плачу около 1 копейки в месяц.

    На смертном одре - передам данные от учётки яндекса дальше.


  1. obsync
    23.06.2026 10:14

    хороший разбор, мы в своё время для себя так и не победили ) чтобы не дергало. в итоге сделали своё решение с блекджеком и без couch github.com/obsyncteam/obsync-ce