NoteHarbor MCP
NoteHarbor — TypeScript
Пример на TypeScript, который подключает Obsidian Markdown к инструментам MCP и расширяет его поиском через PostgreSQL/pgvector.
NoteHarbor разделяет интерфейс MCP и векторное хранилище. Клиент вызывает инструменты MCP, а сервис использует доменную модель и Repository для работы с хранилищем.
Архитектура
MCP Client
│
▼
MCP Tools
(upsert_vector / search_vectors)
│
▼
Vector Service
(src/application/vectorService.ts)
│
▼
VectorRepository port
(src/domain/knowledge.ts)
│
├── 현재 실행 어댑터: in-memory Map 목업
│
└── 운영 전환 지점: PostgreSQL + pgvector
(src/infrastructure/postgres/)Заметка превращается в поисковые данные в следующем порядке:
Obsidian Markdown
→ note chunk
→ externally generated embedding
→ note_chunks.embedding (pgvector)
→ cosine similarity search
→ MCP responseRelated MCP server: second-brain-mcp
Фактический процесс векторизации
upsert_vector — это инструмент для сохранения уже созданного embedding. А как Markdown превращается в chunk и вектор, можно посмотреть в index_note.
Markdown text
→ splitMarkdownIntoChunks()
→ EmbeddingProvider.embed(chunk)
→ normalized number[]
→ NoteChunk
→ VectorService.indexChunk()
→ VectorRepository.save()Основной код разбит по следующим файлам:
chunker.ts: разбивает Markdown на абзацы и применяет максимальную длину
embeddingProvider.ts: детерминированный демонстрационный embedding-провайдер без API-ключа
indexingPipeline.ts: связывает создание chunk, embedding и сохранение
knowledge.ts: порты
EmbeddingProviderиVectorRepositoryindex.ts: регистрирует инструменты MCP
index_note,upsert_vector,search_vectors
Демонстрационный провайдер — это детерминированная реализация для проверки потока, а не модель для качественного смыслового поиска. В реальном сервисе к тому же порту EmbeddingProvider подключается внешняя или локальная модель.
Квантование применяется после создания embedding.
float embedding [-1, 1]
→ clamp
→ int8 = round(value / (1 / 127))
→ 저장: values + scale + zeroPoint
→ 복원: (int8 - zeroPoint) * scaleПример использует симметричное скалярное INT8-квантование.
диапазон значений:
[-1, 1]диапазон квантования:
[-127, 127]scale:1 / 127zeroPoint:0Схема хранит
embedding_int8,embedding_scale,embedding_zero_pointвместе с исходным embeddingСейчас поиск работает с восстановленным float-вектором, а ANN-индекс на основе квантования добавляется при выборе реального адаптера
Реализация находится в quantizer.ts и indexingPipeline.ts. Ответ index_note тоже содержит размерность embedding и число бит квантования.
Почему такая структура
NoteHarbor — это пример, который превращает Obsidian Markdown в доступные для поиска единицы знания и предоставляет эту возможность через инструменты MCP.
Простого строкового поиска недостаточно, чтобы находить связанные материалы с другими формулировками. Поэтому заметка разбивается на небольшие chunk, каждый chunk превращается в embedding, и поиск идёт по смысловой близости.
Квантование нужно, чтобы сделать embedding компактнее.
уменьшает память
уменьшает объём передаваемых данных
удобно для кэша и пакетной обработки в крупной базе знаний
но точность может быть чуть ниже, чем у исходного float
Поэтому у каждого компонента своя роль:
Embedding: превращает смысл текста в числовой вектор
Quantization: снижает точность вектора, чтобы уменьшить затраты на хранение
Vector search: находит близкие векторы и возвращает связанные chunk
MCP: открывает эту функцию как инструмент, который может вызывать LLM-клиент
INT8 выбран потому, что квантование и формат хранения легко объяснить на коде. В реальном сервисе нужно измерять качество поиска, экономию памяти и задержку, а затем выбирать между float32, float16, INT8 и binary.
Текущая реализация — это заглушка (mock) для проверки потока. Она не гарантирует качество смыслового поиска или производительность квантования. В реальной эксплуатации к порту embedding-провайдера подключается настоящая модель, а к порту репозитория — pgvector-адаптер.
Проектирование векторной БД
Единица хранения векторов — NoteChunk.
поле | значение |
| идентификатор из исходного пути и номера chunk |
| исходный путь Obsidian Markdown |
| номер chunk внутри документа |
| текст, который возвращается в результатах поиска |
| вектор, созданный внешней моделью embedding |
| расширяемые данные: теги, статус, атрибуты и т.д. |
Рабочий пример SQL-схемы находится в src/infrastructure/postgres/schema.sql. В базовом примере используется 1536-мерный embedding и HNSW-индекс для cosine distance. При реальном использовании размерность подстраивается под конкретную модель embedding.
Поиск в PostgreSQL выглядит так:
SELECT id, source_path, chunk_index, content, metadata,
1 - (embedding <=> $1::vector) AS score
FROM note_chunks
ORDER BY embedding <=> $1::vector
LIMIT $2;Граница CRUD и ORM-стиля
Векторное хранилище — это не только поиск, но и репозиторий, управляющий жизненным циклом NoteChunk.
Create/Upsert:
upsert_vector,index_note→VectorService.indexChunk()Read:
get_chunk,list_chunksUpdate:
update_chunk→ читает существующий chunk, обновляет поля и квантованное представлениеDelete:
delete_chunkSearch:
search_vectors,search_knowledge
Сейчас адаптером выступает Map в памяти. В production внутренности репозитория заменяются на Drizzle ORM и pg.
db.insert(noteChunks).values(row).onConflictDoUpdate(...)
db.select().from(noteChunks).where(eq(noteChunks.id, id)).limit(1)
db.update(noteChunks).set(values).where(eq(noteChunks.id, id))
db.delete(noteChunks).where(eq(noteChunks.id, id))Инструменты MCP не выполняют SQL напрямую. Вызов идёт по цепочке MCP → VectorService → VectorRepository → Drizzle/pgvector.
Что входит в пример
чтение и поиск по Obsidian Markdown
инструменты MCP:
index_note,search_knowledge,upsert_vector,search_vectorsслои:
MCP → Service → Repository → pgvectorсхема
note_chunksна основе Drizzle ORMсхема PostgreSQL/pgvector и SQL для поиска
граница синхронизации с Notion
dev-сервер Smithery и пример запуска в Docker
Базовая конфигурация запускается без личных данных и без внешних учётных данных — используется заглушка в памяти. При подключении PostgreSQL Map-реализация в src/infrastructure/postgres/postgresVectorRepository.ts заменяется адаптером на Drizzle/pg. README и схема показывают, где именно происходит этот переход.
Версия на Python/GraphQL доступна в noteharbor-python.
Начало работы
npm install
npm run devDocker:
docker build -f Dockerfile.typescript -t noteharbor-mcp-ts .
docker run --rm -p 8081:8081 noteharbor-mcp-tsПочему PostgreSQL + pgvector
Объекты поиска NoteHarbor — это не только векторы. Нужно одновременно работать с реляционными метаданными: исходный путь, номер chunk, теги, статус, информация о синхронизации.
Поэтому в этом примере не добавляется отдельная векторная БД, а в PostgreSQL хранятся вместе:
content: фрагмент исходного текста, который показывается в результатах поискаmetadata: теги, статус, информация об источникеembedding: float-вектор для cosine-поискаembedding_int8: квантованное представление для экономии памяти и трафика
Конкретные причины выбора pgvector:
Совместимость данных: векторная близость и условия по
source_path, тегам, статусу комбинируются в одном SQLСогласованность: метаданные исходного текста и поисковый индекс управляются в одной транзакционной границе
Простота эксплуатации: приложению не нужно отдельно обслуживать PostgreSQL и отдельную векторную БД
Возможности поиска: cosine distance (
<=>) и HNSW-индекс доступны как расширение PostgreSQLПуть масштабирования: сначала единое хранилище, а при росте можно выделить отдельный поисковый адаптер
При большом масштабе поиска выделенная векторная БД может подойти лучше. Здесь главное — показать поток, в котором исходный текст, метаданные и векторный поиск находятся в одной границе приложения.
Как работает поиск
Поиск не сравнивает исходные строки напрямую. Вопрос и chunk заметки помещаются в одно и то же пространство embedding, после чего сравнивается расстояние.
사용자 질문
→ query embedding 생성
→ INT8 양자화 후 복원
→ PostgreSQL/pgvector cosine distance 검색
→ 가까운 NoteChunk 반환
→ sourcePath·content·metadata와 함께 MCP 응답Рабочий пример — инструмент MCP search_knowledge.
index_noteразбивает Markdown на chunk и сохраняет embedding каждого chunk.Пользователь отправляет запрос на естественном языке
query.Тот же
EmbeddingProviderсоздаёт embedding запроса.Запрос квантуется и восстанавливается тем же способом, что и сохранённые векторы.
VectorRepository.search()сортирует chunk по cosine similarity.В результатах — исходный путь, содержимое chunk, метаданные и score.
search_vectors — низкоуровневый инструмент, который принимает уже готовый embedding. search_knowledge — прикладной инструмент, который связывает естественный вопрос с результатами поиска.
Сейчас мок-репозиторий вычисляет cosine similarity в памяти через Map. После перехода на PostgreSQL-адаптер за тем же портом будут использоваться оператор <=> из pgvector и поиск с LIMIT.
Дополнительные технологии и зачем они здесь
технология | зачем используется |
Node.js ESM | чтобы просто запускать TypeScript MCP-пример в текущей среде выполнения Node |
MCP SDK | чтобы регистрировать инструменты |
Zod | для проверки входных данных MCP и конфигурации во время выполнения |
Drizzle ORM | чтобы при подключении PostgreSQL-адаптера получить типобезопасную границу схемы и запросов |
pg | драйвер для перехода на реальный адаптер подключения PostgreSQL |
Smithery CLI | предоставляет путь запуска для разработки и проверки MCP-сервера |
Docker | фиксирует условия запуска Node/MCP в локальной и развёрнутой среде |
chokidar·fast-glob | отвечает за отслеживание изменений в vault Markdown и обход файлов |
gray-matter·marked | для работы с frontmatter Markdown и телом заметки как с единицами знания |
dotenv | чтобы отделить локальные настройки окружения от кода |
Не все зависимости — ядро векторного поиска. Часть — вспомогательные технологии для интеграции с Obsidian и Notion. Центр поискового пути: MCP SDK → Vector Service → Repository → pgvector.
Почему выбраны эти технологии
технология | причина выбора |
Obsidian Markdown | исходник — обычные текстовые файлы: высокая управляемость и переносимость, знание не привязано к конкретному SaaS |
MCP | чтобы не писать отдельную интеграцию под каждого LLM-клиента, а открыть один и тот же инструмент знаний через стандартный интерфейс |
TypeScript | естественная связка с MCP SDK, границы входа и выхода инструментов управляются типами |
PostgreSQL | чтобы согласованно хранить метаданные документов, статусы и результаты поиска в одном хранилище и иметь путь к production |
pgvector | чтобы без отдельной векторной БД работать с метаданными исходного текста и векторным поиском внутри PostgreSQL |
Notion adapter | чтобы показать границу: Notion не является исходным хранилищем, но при необходимости фрагменты знаний синхронизируются во внешний workspace |
Docker | чтобы сделать условия запуска PostgreSQL и MCP одинаковыми в локальной и развёрнутой среде |
Суть не в том, чтобы навесить как можно больше инструментов. Суть в том, что исходник сохраняется в Markdown, производные данные для поиска лежат в PostgreSQL/pgvector, а LLM через MCP получает только нужные функции.
Поэтому этот проект — не система, где Obsidian, Notion и PostgreSQL одновременно являются источниками.
Obsidian Markdown: исходное знание
PostgreSQL/pgvector: производный индекс для поиска
Notion: опциональная внешняя цель синхронизации
MCP: граница доступа для LLM
Ключевые проектные решения
сохранение исходного Markdown
разделение инструментов MCP и сервисного слоя
доменная модель
NoteChunkи портVectorRepositoryграница хранилища, заменяемая на PostgreSQL/pgvector
без личного vault и учётных данных
Это публичный пример для изучения структуры MCP и поиска по знаниям.
Лицензия
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides semantic search capability over Obsidian vaults and exposes recent notes as resources to Claude through the MCP protocol.9
- AlicenseNot gradedqualityCmaintenanceTurns an Obsidian vault into semantic memory for coding agents, providing read-only semantic search and a human-approved write workflow via MCP.5MIT
- AlicenseNot gradedqualityAmaintenanceConnects AI assistants to an Obsidian vault as a semantic knowledge graph, enabling graph navigation, semantic search, and content operations through MCP.12456MIT
- AlicenseNot gradedqualityCmaintenanceExposes an Obsidian notes vault as MCP services, enabling AI assistants to search, read, create, update, and delete notes and folders.241MIT
Related MCP Connectors
Markdown-based note-taking with a hosted MCP server. Your notes serve you and your AI.
Token-efficient MCP memory for Markdown vaults. Tiered search, GraphRAG, AI memories.
Search and reason over your Obsidian-style Markdown vault, right from ChatGPT.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/kris-atelier/noteharbor-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server