Я веду 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-токен.
Общий порядок такой:
Поднять CouchDB.
Создать базу для LiveSync.
Настроить CORS так, чтобы Obsidian LiveSync мог подключаться к CouchDB.
Подключить Self-hosted LiveSync в Obsidian.
Проверить синхронизацию хотя бы на одном-двух устройствах.
Поднять MCP-сервер.
Настроить авторизацию.
Подключить 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)

apeshand
23.06.2026 10:14Я.Клауд давал пробные 3т.р. рублей на счёт, там создал бакет на 50Гб, установил в obsidian Remotely Save, туда втолкнул креды от бакета и теперь на всех моих устройствах нужные мне заметки.
За свои заметки плачу около 1 копейки в месяц.
На смертном одре - передам данные от учётки яндекса дальше.

obsync
23.06.2026 10:14хороший разбор, мы в своё время для себя так и не победили ) чтобы не дергало. в итоге сделали своё решение с блекджеком и без couch github.com/obsyncteam/obsync-ce
prdenisov
класс, спасибо за инфу. Обсидиан юзаю уже года 3,5, наверное, в связке с ИИ крайне интересный комбайн получается
Undesired Автор
Я от случая к случаю использовал, было неудобно, что нет синхронизации между разными тачками. Потом поставил Livesync и Obsidian стал превращаться уже в рабочий инструмент. А потом осознал, что для ЛЛМ md файлы отлично использовать и как память и как заметки. Решил поэкспериментировать...и вот получился удобный инструмент, который я использую на ежедневной основе.