Skip to main content
Glama

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

Три публичных примера

  1. MCP: инструменты upsert_vector, search_vectors

  2. GraphQL: мутация indexChunk, запрос vectorSearch

  3. PostgreSQL/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-mcp

POSTGRES_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, GraphQL indexChunkVectorService.index_chunk()

  • Read: MCP get_chunk·list_chunks, GraphQL noteChunk·noteChunks

  • Update: MCP·GraphQL updateChunk → после чтения существующей записи обновляются только изменённые поля

  • Delete: MCP·GraphQL deleteChunk

  • Search: MCP search_vectors, GraphQL vectorSearch

Текущий адаптер — это 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, косинусное расстояние (<=>), индекс HNSW

  • Docker: фиксирует условия запуска 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

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides tools for ingesting documents into a local vector database and retrieving relevant information via semantic search, enabling retrieval-augmented generation for MCP clients.
    6
  • A
    license
    Not graded
    quality
    B
    maintenance
    Indexes local Markdown/text files into a SQLite database with vector embeddings and provides MCP tools for semantic search without cloud dependencies.
    GPL 3.0
  • A
    license
    Not graded
    quality
    A
    maintenance
    Provides MCP tools for semantic search over personal knowledge sources using pluggable embeddings and local vector indexing.
    1
    MIT

View all related MCP servers

Related MCP Connectors

  • 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.

  • Token-efficient MCP memory for Markdown vaults. Tiered search, GraphRAG, AI memories.

View all MCP Connectors

Latest Blog Posts

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-python'

If you have feedback or need assistance with the MCP directory API, please join our Discord server