brain-mcp
brain-mcp
Автор иконки: wenmeiZhou на iStock.
MCP-сервер, который предоставляет markdown-хранилище второго мозга, организованное по методу PARA (совместимое с Obsidian), в виде набора инструментов для чтения и одного ограниченного инструмента для записи (capture, который только создаёт новые заметки в 00-inbox/). Работает как Docker-контейнер, используется через streamable-HTTP клиентами Claude Code, opencode и другими MCP-клиентами.
Полная спецификация поведения: см. brain-mcp-spec.md в этом репозитории (или там, где вы его храните), если вам нужно «почему» за тем или иным проектным решением.
Примечания о парсере CONVENTIONS.md
brain_structure() читает перечисления type/status/domain напрямую из вашего файла 90-meta/CONVENTIONS.md, а не захардкоживает их (см. _extract_enum_values в src/brain_mcp/vault.py). Он был проверен на реальном файле хранилища: в этом файле три перечисления указаны как жирные встроенные метки под одним заголовком ## Enums (**type:** \note`, `project`, ...), а не каждое в отдельном подзаголовке, поэтому _extract_enum_values сначала пробует такую форму (ограничиваясь абзацем самой метки, чтобы не захватывать посторонние слова в кавычках-бэктиках в тексте ниже — например, «domain— основная ось запросов...»), а затем переходит к эвристике на основе заголовков для хранилищ, где перечисления описаны иначе. Если вы позже измените структуру раздела Enums вCONVENTIONS.md`, перепроверьте этот парсер — сервер громко падает при запуске, а не переходит к плохим значениям по умолчанию, если не может разобрать непустой список значений для всех трёх полей.
Формат uid: хранилище, на котором это проверялось, в настоящее время содержит противоречие в собственном CONVENTIONS.md — пример во frontmatter показывает UUIDv4, в тексте двумя строками ниже сказано, что реальный формат — YYYYMMDD-HHmm (+ буква при коллизиях в одну минуту), а реальные заметки на диске используют три разные схемы (UUIDv4 в одной заметке во входящих, 00000000-000N-заглушки в мета-документах, последовательные счётчики YYYYMMDD-000N в файлах _index.md). capture() генерирует UUIDv4 — это то, что просила исходная спецификация, соответствует текущему коду и сохраняет осмысленность поиска по короткому префиксу в read_note (≥8 символов), чего не было бы с низкоэнтропийным датированным id, где всё за один день имеет общий префикс. Если в вашем собственном CONVENTIONS.md описан другой формат uid, это стоит согласовать на стороне хранилища — сервер это автоматически не делает.
Related MCP server: Obsidian MCP Server
Требования
Структура PARA и схема frontmatter хранилища, как описано в собственном
90-meta/CONVENTIONS.mdхранилища.Docker (или Docker Compose) на Unraid-машине, или Python 3.12 +
uvлокально для разработки.ripgrepв PATH (встроен в образ контейнера; установите отдельно для локальной разработки).
Конфигурация
Вся конфигурация через переменные окружения — ничего о конкретном хранилище (путь, имя, токен) не захардкожено, поэтому один и тот же образ обслуживает любое количество соседних хранилищ как отдельные контейнеры.
Переменная | Обязательная | По умолчанию | Значение |
| да | — | Абсолютный путь к корню хранилища в контейнере |
| да | — | Имя экземпляра, например |
| да | — | Bearer-токен, обязательный для каждого MCP-запроса |
| нет |
| Порт прослушивания |
| нет |
| Адрес прослушивания |
| нет |
|
|
Скопируйте .env.example в .env и заполните BRAIN_NAME, BRAIN_VAULT_PATH (путь на хосте к вашему хранилищу) и BRAIN_TOKEN (случайный секрет — openssl rand -hex 32 подойдёт) перед запуском Compose.
Локальная разработка
uv sync --dev # or: python3 -m venv .venv && .venv/bin/pip install -e ".[dev]"
uv run pytest # or: .venv/bin/python -m pytestТесты полностью выполняются на синтетическом фикстурном хранилище, созданном в tests/conftest.py — никогда на реальных данных.
Чтобы запустить сервер локально на реальном (или тестовом) каталоге хранилища:
export BRAIN_ROOT=/path/to/vault
export BRAIN_NAME=personal
export BRAIN_TOKEN=dev-token
uv run brain-mcpЗапуск на Unraid
cp .env.example .env # fill in BRAIN_NAME, BRAIN_VAULT_PATH, BRAIN_TOKEN
docker compose up -d --build # or: docker compose pull && docker compose up -d
curl http://<unraid-host>:3100/health--build собирает из этого репозитория; pull вместо этого загружает тот же образ, предварительно собранный из GHCR (см. «Установка как приложение Unraid» ниже) — оба варианта дают локальный тег ghcr.io/sipho102/brain-mcp:latest.
Файл compose монтирует BRAIN_VAULT_PATH в режиме только для чтения и поверх него монтирует только 00-inbox/ в режиме чтения-записи:
volumes:
- ${BRAIN_VAULT_PATH}:/vault:ro
- ${BRAIN_VAULT_PATH}/00-inbox:/vault/00-inbox:rwЭто намеренно и критически важно — даже ошибка в пути записи не может затронуть ничего за пределами входящих, независимо от того, что думает код Python. Не упрощайте это до единого монтирования чтения-записи.
Установка как приложение Unraid вместо этого
Если вы предпочитаете управлять этим через вкладку Docker в Unraid, как любым другим приложением — форма вместо редактирования .env, кнопки Start/Stop/Update после — для этого есть шаблон в unraid/brain-mcp.xml. .github/workflows/publish.yml собирает образ этого репозитория и публикует его в GHCR (ghcr.io/sipho102/brain-mcp:latest) при каждом push в main, и шаблон тянет его напрямую — без клонирования или сборки на Unraid-машине вообще.
Сделайте шаблон доступным для Unraid:
Рекомендуется — на вкладке Docker нажмите Add Container и вставьте URL сырого шаблона этого репозитория прямо в поле шаблона:
https://raw.githubusercontent.com/sipho102/brain-mcp/main/unraid/brain-mcp.xmlТак ничего не записывается в локальную папку шаблонов Unraid, поэтому не остаётся лишнего файла, который мог бы конфликтовать позже — см. предупреждение ниже об альтернативном методе.Или скопируйте его в локальную папку шаблонов Unraid через SSH:
curl -o /boot/config/plugins/dockerMan/templates-user/brain-mcp.xml \ https://raw.githubusercontent.com/sipho102/brain-mcp/main/unraid/brain-mcp.xmlЗатем он появится в Docker → Add Container → выпадающем списке шаблонов — но см. примечание сразу после Add Container об удалении этого файла после создания контейнера.
В любом случае вы получите форму для пути к хранилищу, пути к входящим (должен быть <путь к хранилищу>/00-inbox — шаблон не может вывести его за вас), имени экземпляра и bearer-токена; всё остальное предзаполнено разумными значениями по умолчанию в «расширенном виде».
Если вы использовали метод локального копирования выше, удалите этот файл-затравку после добавления контейнера:
rm /boot/config/plugins/dockerMan/templates-user/brain-mcp.xmlКогда вы нажимаете Apply в Add Container, Unraid сохраняет второй файл с вашими реальными значениями — my-brain-mcp.xml, рядом с пустым, который вы скачали — и оба объявляют одно и то же имя контейнера. С двумя шаблонами, претендующими на это имя, Update может в итоге пересоздать контейнер из пустого оригинала вместо вашего сохранённого, стирая BRAIN_NAME/BRAIN_TOKEN/пути и оставляя его неработоспособным. Как только my-brain-mcp.xml существует (проверьте ls /boot/config/plugins/dockerMan/templates-user/), файл-затравка выполнил свою задачу и больше не нужен — удалите его, чтобы не было двусмысленности. После этого нажатие Update потянет самое свежее из ghcr.io/sipho102/brain-mcp:latest, используя вашу сохранённую конфигурацию, как и ожидается.
Обслуживание второго хранилища
Один контейнер обслуживает одно хранилище — намеренно нет списка мульти-хранилищных сервисов в docker-compose.yml, и нет мульти-хранилищной формы в шаблоне Unraid. На пути приложения Unraid это просто означает повторное Add Container из того же шаблона с другим именем/путями/токеном/портом. На пути Compose скопируйте этот каталог развёртывания (или просто docker-compose.yml + .env) в другое место, заполните в копии .env другие BRAIN_NAME, BRAIN_VAULT_PATH, BRAIN_TOKEN и PORT, и запустите docker compose up -d --build оттуда. Тот же образ (brain-mcp:latest), независимые контейнеры.
Пользователь контейнера / права доступа
Контейнер работает от непривилегированного пользователя, UID:GID 99:100 по умолчанию (Unraid nobody:users) — переопределите при сборке через BRAIN_UID/BRAIN_GID в .env, если вашему ресурсу нужны другие права владельца. Этот пользователь должен иметь доступ на запись к 00-inbox/ на хостовом ресурсе.
Подключение клиента
Claude Code
claude mcp add --transport http --scope user brain \
http://<unraid-host>:3100/mcp \
--header "Authorization: Bearer <token>"Затем /mcp в сессии должен показать все шесть инструментов.
Известная особенность: у Claude Code были повторяющиеся ошибки, когда заголовки, заданные через --header, не отправлялись при установлении сессии, что приводило к 401, хотя curl с тем же токеном работал. Если вы столкнулись с этим, запишите объект headers напрямую в JSON-конфиг (~/.claude/mcp_servers.json или соответствующий файл области):
{
"mcpServers": {
"brain": {
"type": "http",
"url": "http://<unraid-host>:3100/mcp",
"headers": {
"Authorization": "Bearer <token>"
}
}
}
}(type также принимает streamable-http как псевдоним для http в JSON-конфигах.)
opencode
opencode по умолчанию пытается выполнить OAuth-обнаружение на удалённых MCP-серверах и игнорирует статический bearer-токен, если вы явно не отключите это:
{
"mcp": {
"brain": {
"type": "remote",
"url": "http://<unraid-host>:3100/mcp",
"oauth": false,
"headers": {
"Authorization": "Bearer <token>"
}
}
}
}Без oauth: false opencode попытается выполнить (и провалит) OAuth-рукопожатие вместо использования заголовка.
Клиенты без поля заголовка вообще
Некоторые интерфейсы MCP-клиентов принимают только имя, транспорт и URL — нет способа задать пользовательский заголовок Authorization. Для таких поместите токен в URL:
http://<unraid-host>:3100/mcp?token=<token>Сервер сначала проверяет заголовок Authorization, а затем переходит к параметру запроса ?token=, так что это работает везде, где работает и конфигурация с заголовком выше. Стоит знать, прежде чем полагаться на это: токен в URL может оказаться в большем количестве мест, чем заголовок — в сохранённой конфигурации клиента, в истории браузера, если URL когда-либо открыт напрямую, в истории оболочки, если вы вставили его в терминал. Журналы доступа здесь не проблема (журнал доступа uvicorn выключен), но относитесь к самому URL как к носителю секрета, так же, как и к самому токену.
Инструменты
Шесть инструментов, намеренно небольших (схемы инструментов стоят контекста клиента):
brain_structure()— ориентация: папки PARA + счётчики, живые перечисления изCONVENTIONS.md, схема frontmatter, полный текст соглашений, количество заметок. Вызывайте это первым в сессии.search_notes(query, domain, type, status, para, tag, limit)— полнотекстовый поиск (ripgrep) с фильтрацией по frontmatter. Возвращает метаданные + фрагмент ~200 символов, никогда полные тела.read_note(identifier)— полная заметка по пути относительно хранилища, полномуuidили однозначному префиксуuid(≥8 символов).list_notes(para, domain, status, type, limit)— просмотр только метаданных, без поиска по содержимому.get_backlinks(identifier)— заметки, ссылающиеся на эту, с контекстной строкой.capture(title, body, domain, tags, source, links)— единственная запись: создаёт новую заметку в00-inbox/. Никогда не перезаписывает, никогда не касается ничего за пределами входящих.
Что это намеренно не делает
Нет семантического поиска/эмбеддингов, нет доступа на запись за пределами 00-inbox/, нет зависимости от Obsidian Local REST API (читает файловую систему напрямую), нет получения документов paperless-ngx (возвращает ID документов из frontmatter, чтобы клиент мог связать их с отдельным MCP-сервером paperless), нет операций с git. См. brain-mcp-spec.md §2 для обоснования.
This server cannot be deployed
Maintenance
Related MCP Connectors
Serve a folder of Markdown notes as an MCP server: hybrid search, reading, and sourced answers.
Markdown-based note-taking with a hosted MCP server. Your notes serve you and your AI.
OAuth-protected, read-only-by-default MCP server for provenance-labeled QuillCaddie project memory.
Notes and memory assistant: one Markdown vault that Claude, ChatGPT and any MCP client can share.
Related MCP Servers
- AlicenseAqualityAmaintenanceA generic Markdown vault MCP server with FTS5 full-text search, semantic vector search, frontmatter-aware indexing, incremental reindexing, and non-markdown attachment support that exposes search, read, write, and edit tools.44230 PyPI35MIT
- AlicenseNot gradedqualityCmaintenanceExposes an Obsidian notes vault as MCP services, enabling AI assistants to search, read, create, update, and delete notes and folders.12 npm1MIT
- AlicenseNot gradedqualityBmaintenanceExposes a personal markdown-based second brain (Obsidian-style) as an MCP server, enabling agents to search, read, and write notes with privacy controls.MIT
- AlicenseAqualityBmaintenanceEnables MCP clients to read, write, search, and manage notes, canvases, kanban boards, and other Obsidian vault content over a network, without requiring the Obsidian desktop app.33MIT