NoteHarbor MCP
NoteHarbor MCP
Пример на Python для получения заметок Obsidian через MCP и GraphQL, расширяемый с помощью PostgreSQL/pgvector. Личные vault, реальные документы и API-ключи не включены.
Исходный материал NoteHarbor — это Markdown-файлы. Для поиска создаются только необходимые данные, а исходники сохраняются как есть.
Критерии этого проекта
Local first: исходные Markdown остаются локально, а внешние сервисы — лишь подключаемые опции.
Source preserving: результаты поиска, эмбеддингов и синхронизации не заменяют исходники.
Privacy by boundary: реальные vault, личные записи и API-ключи находятся за пределами публичного проекта.
Model neutral: генератор эмбеддингов и Vector DB не привязываются к конкретному поставщику.
Small and replaceable: адаптеры и сервисный слой остаются небольшими и заменяемыми.
Related MCP server: Notes RAG MCP Server
Три публичных примера
MCP: инструменты
upsert_vector,search_vectorsGraphQL: мутация
indexChunk, запросvectorSearchPostgreSQL/pgvector: модели SQLAlchemy, порт Repository, среда разработки Docker
Это пример для изучения структуры, а не рабочий сервис. Базовый Repository работает в памяти; также приведены точки перехода на PostgreSQL/pgvector и примеры SQL.
Быстрый старт
uv syncЗапуск примера MCP:
uv run noteharborЗапуск PostgreSQL через Docker
docker compose up -d postgresФайл docker-compose.yml определяет образ pgvector/pgvector и PostgreSQL для разработки Python MCP.
# PostgreSQL만
docker compose up -d postgres
# Python MCP까지
docker compose up --build python-mcpPOSTGRES_URL — это место для настройки подключения к реальной БД. Сейчас запуск по умолчанию выполняется на моке.
Пример GraphQL
Схема GraphQL находится в noteharbor/api/graphql_schema.py. Результат get_schema() можно подключить к внешнему ASGI-серверу.
Пример операции:
mutation {
indexChunk(
sourcePath: "sample.md"
content: "Obsidian knowledge"
embedding: [1.0, 0.0]
)
}
query {
vectorSearch(embedding: [0.9, 0.1], limit: 5) {
sourcePath
content
score
}
}Границы CRUD и ORM-стиля
Repository отвечает не только за поиск, но и за весь жизненный цикл NoteChunk — от создания до удаления.
Create/Upsert: MCP
upsert_vector, GraphQLindexChunk→VectorService.index_chunk()Read: MCP
get_chunk·list_chunks, GraphQLnoteChunk·noteChunksUpdate: MCP·GraphQL
updateChunk→ после чтения существующей записи обновляются только изменённые поляDelete: MCP·GraphQL
deleteChunkSearch: MCP
search_vectors, GraphQLvectorSearch
Текущий адаптер — это in-memory мок для проверки работы. Реальное хранение размещается за границей SQLAlchemy ORM. В реальном адаптере PostgreSQL MockPostgresVectorRepository заменяется на сеансовые операции следующего вида.
Код реального ORM-потока можно посмотреть в noteharbor/infrastructure/postgres/sqlalchemy_repository.py. Этот адаптер реализует тот же порт VectorRepository, используя Session.get, select, update, delete. Запуск по умолчанию по-прежнему моковый, поэтому пример можно читать и тестировать без подключения к PostgreSQL.
session.get(NoteChunkModel, chunk_id)
session.scalars(select(NoteChunkModel).limit(limit)).all()
session.execute(update(NoteChunkModel).where(NoteChunkModel.id == chunk_id).values(...))
session.execute(delete(NoteChunkModel).where(NoteChunkModel.id == chunk_id))API не работает с SQL напрямую, а передаёт CRUD и поиск по цепочке MCP/GraphQL → VectorService → VectorRepository → SQLAlchemy/pgvector.
Назначение
Этот репозиторий — образец Python-архитектуры, в которой один исходный Markdown-документ запрашивается через один и тот же сервис векторного поиска как через MCP, так и через GraphQL.
Вместо того чтобы заранее выбирать конкретного поставщика эмбеддингов или векторную БД, фокус сделан на явных точках замены.
MCP / GraphQL API
→ VectorService
→ VectorRepository port
→ 현재: in-memory MockPostgresVectorRepository
→ 전환: PostgreSQL + pgvectorОтветственность за векторизацию и поиск
Текущий Python-пример не создаёт эмбеддинги напрямую. Мутация indexChunk и инструмент upsert_vector принимают и сохраняют эмбеддинги list[float], созданные извне.
Причины выноса генерации эмбеддингов:
чтобы не привязывать модель эмбеддингов к одной из: OpenAI, Voyage или локальная модель
чтобы исключить API-ключи и личные данные из публичного примера
чтобы разделить ответственность API-слоя и хранилища поиска
чтобы в реальном сервисе конвейер чанкинга и генерации эмбеддингов можно было заменить отдельным worker'ом
Поиск выполняется в следующем порядке:
사용자 query embedding
→ GraphQL vectorSearch 또는 MCP search_vectors
→ VectorService.search()
→ Repository.search()
→ cosine similarity 계산
→ score가 높은 NoteChunk 반환Сейчас MockPostgresVectorRepository в repository.py воспроизводит этот поток в памяти. В реальном адаптере PostgreSQL косинусное расстояние вычисляется через embedding <=> :query_embedding, а 1 - distance возвращается как score.
Почему PostgreSQL + pgvector
NoteChunk — это не только значение с вектором, но и запись, содержащая исходный путь, порядковый номер чанка, текст и метаданные. Сочетание PostgreSQL и pgvector позволяет обрабатывать реляционные условия и поиск по векторной схожести в одном хранилище и в границах SQL.
PostgreSQL: метаданные исходников, состояние, информация о синхронизации и управление транзакциями
pgvector: колонка
vector, косинусное расстояние (<=>), индекс HNSWDocker: фиксирует условия запуска pgvector в среде разработки
SQLAlchemy Repository: точка замены хранилища
При росте масштаба поиска может оказаться более подходящей специализированная векторная БД. Здесь показан поток, в котором информация о документах и векторный поиск обрабатываются в одном хранилище.
Область квантования
В текущий Python-репозиторий реализация квантования не включена. Входные эмбеддинги принимаются как есть — значениями float — и используются для поиска; это выбор, сделанный, чтобы в первую очередь показать модель-нейтральную границу Repository.
Если квантование добавляется, предусматривается отдельный порт EmbeddingQuantizer, а этапы float32 → INT8/float16 → сохранение/восстановление размещаются между indexing worker'ом и адаптером Repository. Поскольку способ квантования следует выбирать после измерения качества поиска, памяти и задержки, этот пример не утверждает, что оно уже реализовано.
Связь двух примеров NoteHarbor
noteharbor-mcp: инструменты TypeScript MCP и поток эмбеддингов и INT8-квантования
noteharbor-python: Python MCP·GraphQL API и граница VectorService/Repository
Оба репозитория — это примеры одной и той же идеи на разных языках и через разные способы API; они не содержат реальных личных vault или рабочих данных.
Дополнительные технологии и причины их использования
Технология | Причина использования |
uv | для быстрого воспроизведения Python-зависимостей, виртуального окружения и lock-файла и использования того же пути установки в Docker |
FastMCP | для краткой и ясной демонстрации связи Python-функций с инструментами MCP |
Pydantic | для валидации входных моделей и настроек на границе API |
SQLAlchemy | чтобы Repository не был привязан к конкретному способу выполнения SQL и имел границу адаптера PostgreSQL |
psycopg | для обеспечения подключения к PostgreSQL из Python |
pgvector Python package | для представления типа vector PostgreSQL в моделях SQLAlchemy |
Strawberry GraphQL | для создания примера, в котором один и тот же VectorService доступен через GraphQL Query/Mutation |
Docker Compose | для совместного воспроизведения среды разработки PostgreSQL с включённым pgvector и Python MCP |
Каждая технология выбрана, чтобы описать разделение ролей API, сервиса, хранилища и среды разработки.
Структура проекта
.
├── noteharbor/
│ ├── mcp_server.py
│ ├── api/graphql_schema.py
│ ├── application/vector_service.py
│ ├── domain/
│ └── infrastructure/
│ ├── notion/mock_adapter.py
│ └── postgres/
│ ├── models.py
│ ├── repository.py
│ └── sqlalchemy_repository.py
├── tests/test_vector_repository.py
├── Dockerfile
├── docker-compose.yml
└── pyproject.tomlЛицензия
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
- TaprootOAuthcom.taproothq
Persistent memory layer for AI tools. Save and recall notes across Claude and other MCP clients.
MCP-native notes and memory for ChatGPT, Claude, and other AI tools.
Search, read, and write your Apple Notes from ChatGPT/Claude via a local Mac agent + MCP relay.
Hosted MCP memory: save sessions/decisions once, search from Claude, Cursor, ChatGPT. EU-hosted FTS.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceProvides tools for ingesting documents into a local vector database and retrieving relevant information via semantic search, enabling retrieval-augmented generation for MCP clients.6-
- FlicenseNot gradedqualityAmaintenanceEnables semantic search over personal markdown notes by indexing them into a vector database and exposing search, reindex, and status tools via MCP.-
- AlicenseNot gradedqualityAmaintenanceProvides MCP tools for semantic search over personal knowledge sources using pluggable embeddings and local vector indexing.1MIT
- FlicenseNot gradedqualityCmaintenanceEnables semantic search and related-note discovery across an Obsidian vault via MCP, providing RAG context blocks for natural language queries.-