Skip to main content
Glama

NoteHarbor MCP — TypeScript

Obsidian MarkdownをMCPツールとして接続し、PostgreSQL/pgvector検索で拡張するTypeScriptの例です。

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 response

Related MCP server: second-brain-mcp

実際のベクトル化フロー

upsert_vectorは、すでに作成したembeddingを保存するツールです。Markdownがチャンクとベクトルに変わる過程はindex_noteで確認できます。

Markdown text
  → splitMarkdownIntoChunks()
  → EmbeddingProvider.embed(chunk)
  → normalized number[]
  → NoteChunk
  → VectorService.indexChunk()
  → VectorRepository.save()

主要なコードは次のファイルに分かれています。

  • chunker.ts: Markdownを段落単位で分割し、最大長を適用

  • embeddingProvider.ts: APIキーなしで動作する決定的なデモEmbeddingプロバイダー

  • indexingPipeline.ts: チャンク生成・Embedding・保存を接続

  • knowledge.ts: EmbeddingProviderVectorRepositoryのポート

  • index.ts: index_noteupsert_vectorsearch_vectors MCPツールを登録

デモプロバイダーはフローを確認するための決定的な実装です。意味ベースの検索品質を提供するモデルではなく、実際のサービスでは同じ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 / 127

  • zeroPoint: 0

  • 元のEmbeddingとともにembedding_int8embedding_scaleembedding_zero_pointを保存するようにスキーマを定義

  • 現在の参照検索は復元可能なfloatベクターを使用し、量子化ANNインデックスは実際のアダプター選択時に追加

実装はquantizer.tsindexingPipeline.tsにあります。index_note応答にもEmbedding次元と量子化ビット数が含まれます。

なぜこのように構成したのか

NoteHarborはObsidian Markdownを検索可能な知識単位に変換し、その機能をMCPツールとして提供する例です。

単純な文字列検索だけでは、表現が異なる関連内容を見つけるのは困難です。そこでノートを小さなチャンクに分割し、各チャンクをEmbeddingに変換して意味が近い内容を検索できるようにします。

量子化はこのEmbeddingをより小さな表現で保持するための選択です。

  • メモリとストレージ容量を削減

  • ベクター転送量を削減

  • 大規模ナレッジベースでキャッシュとバッチ処理に有利

  • 代わりに元のfloatより精度が低くなる可能性がある

そこで、各構成要素の役割を次のように分けました。

  1. Embedding: テキストの意味を数値ベクターで表現

  2. Quantization: ベクターの精度を下げて保存コストを削減

  3. Vector search: 近いベクターを見つけて関連チャンクを返す

  4. MCP: この機能をLLMクライアントが呼び出せるツールとして公開

このプロジェクトでINT8を選択した理由は、量子化の原理と保存形式をコードで説明しやすいからです。実際のサービスでは、検索品質・メモリ削減・レイテンシーを測定した後、float32・float16・INT8・binaryのいずれかを選択する必要があります。

現在の実装はフローを確認するためのモックアップです。意味ベースの検索品質や量子化パフォーマンスを保証するものではなく、実際の運用ではEmbeddingプロバイダーとpgvectorアダプターを接続する必要があります。

ベクターDB設計

ベクター保存単位はNoteChunkです。

フィールド

意味

id

元のパスとチャンク順序で作成した識別子

sourcePath

Obsidian Markdownの元のパス

chunkIndex

ドキュメント内のチャンク順序

content

検索結果として返すテキスト

embedding

外部Embeddingモデルが生成したベクター

metadata

タグ・ステータス・元の属性などの拡張情報

実行可能なSQL設計の例はsrc/infrastructure/postgres/schema.sqlにあります。基本的な例は1,536次元のEmbeddingとコサイン距離用のHNSWインデックスを使用し、実際の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のライフサイクルを管理するRepositoryです。

  • Create/Upsert: upsert_vectorindex_noteVectorService.indexChunk()

  • Read: get_chunklist_chunks

  • Update: update_chunk → 既存のチャンクを読み取り、変更フィールドと量子化表現を一緒に更新

  • Delete: delete_chunk

  • Search: search_vectorssearch_knowledge

現在の実行アダプターはMapです。運用環境ではRepository内部の実装を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の順序でCRUDと検索を渡します。

含まれるサンプル

  • Obsidian Markdownの一覧・読み取り・検索

  • index_notesearch_knowledgeupsert_vectorsearch_vectors MCPツール

  • MCP → Service → Repository → pgvector階層

  • Drizzle ORMベースのnote_chunksスキーママッピング

  • PostgreSQL/pgvectorスキーマと検索SQL

  • Notion同期境界

  • Smithery開発サーバーとDocker実行例

現在のデフォルト実行は、個人データと外部資格情報を含まないメモリモックアップです。PostgreSQL接続では、src/infrastructure/postgres/postgresVectorRepository.tsMap実装をDrizzle/pgベースのアダプターに置き換えます。READMEとスキーマは、その移行ポイントを公開するためのサンプルです。

Python/GraphQLバージョンはnoteharbor-pythonで確認できます。

開始

npm install
npm run dev

Docker:

docker build -f Dockerfile.typescript -t noteharbor-mcp-ts .
docker run --rm -p 8081:8081 noteharbor-mcp-ts

なぜPostgreSQL + pgvectorなのか

NoteHarborの検索対象はベクターだけのデータではありません。元のパス、チャンク順序、タグ、状態、同期情報などのリレーショナルメタデータを一緒に扱う必要があります。

そこで、このサンプルでは別のベクターDBを追加するのではなく、PostgreSQLに次のものをまとめて配置します。

  • content: 検索結果として表示する原文の断片

  • metadata: タグ・状態・元の情報

  • embedding: コサイン検索用のfloatベクター

  • embedding_int8: 保存・転送コストを削減するための量子化表現

pgvectorを選択した具体的な理由は次のとおりです。

  • データ結合: ベクター類似度とsource_path、タグ、状態条件を1つのSQLで組み合わせられる

  • 一貫性: 原文メタデータと検索インデックスを同じトランザクション境界で管理できる

  • 運用の単純さ: アプリケーションがPostgreSQLと別のベクターDBをそれぞれ運用する必要がない

  • 検索機能: コサイン距離(<=>)とHNSWインデックスをPostgreSQL拡張として使用できる

  • 拡張パス: 初期は単一ストレージで開始し、規模が大きくなったときに検索専用アダプターを分離できる

検索規模が大きくなると、専用のベクターDBがより適している場合があります。ここでは、元のテキスト、メタデータ、ベクター検索を1つのアプリケーション境界で扱うフローを示すことに意味があります。

検索はどのように動作するか

検索は元の文字列を直接比較するのではなく、質問とノートチャンクを同じEmbedding空間に置き、距離を比較します。

사용자 질문
  → query embedding 생성
  → INT8 양자화 후 복원
  → PostgreSQL/pgvector cosine distance 검색
  → 가까운 NoteChunk 반환
  → sourcePath·content·metadata와 함께 MCP 응답

実行可能なサンプルはsearch_knowledge MCPツールです。

  1. index_noteがMarkdownをチャンクに分割し、各チャンクのEmbeddingを保存します。

  2. ユーザーが自然言語queryを送信します。

  3. 同じEmbeddingProviderでクエリEmbeddingを生成します。

  4. クエリを保存ベクターと同じ方法で量子化・復元します。

  5. VectorRepository.search()がコサイン類似度基準で近いチャンクをソートします。

  6. 検索結果には元のパス、チャンク内容、メタデータ、スコアが含まれます。

search_vectorsはすでに作成されたEmbeddingを直接受け取る低レベルツールで、search_knowledgeは自然言語の質問から検索結果までを接続するアプリケーションレベルのツールです。

現在のモックRepositoryはメモリMapでコサイン類似度を計算します。PostgreSQLアダプターに切り替えると、同じポートの背後でpgvectorの<=>演算とLIMIT検索を使用します。

追加技術と投入理由

技術

投入理由

Node.js ESM

TypeScript MCPサンプルを現在のNodeランタイム方式で単純に実行するため

MCP SDK

index_notesearch_knowledgeupsert_vectorsearch_vectorsツールを標準MCPサーバーとして登録するため

Zod

MCP入力値と設定値をランタイムで検証するため

Drizzle ORM

PostgreSQLアダプターを接続するときに型安全なスキーマ・クエリ境界を提供するため

pg

実際のPostgreSQL接続アダプターに切り替えるときに使用するドライバー

Smithery CLI

MCPサーバーを開発・検証する実行パスを提供するため

Docker

ローカルとデプロイ環境のNode/MCP実行条件を固定するため

chokidar・fast-glob

Markdown vaultの変更検知とファイル探索を担当するため

gray-matter・marked

Markdown frontmatterと本文を知識チャンクとして扱うため

dotenv

ローカル環境設定をコードと分離するため

すべての依存関係がベクター検索の核心ではありません。一部はObsidian・Notion連携のための補助技術であり、検索パスの中心はMCP SDK → Vector Service → Repository → pgvectorです。

技術を選択した理由

技術

選択理由

Obsidian Markdown

元のファイルがプレーンテキストファイルであるため、所有権と可搬性が高く、特定のSaaSに知識の元を依存させないため選択

MCP

LLMクライアントごとに別の連携コードを作成せず、同じ知識ツールを標準インターフェースとして公開するため選択

TypeScript

MCP SDKとの接続が自然で、ツールの入力・出力境界を型で管理するため選択

PostgreSQL

ドキュメントメタデータ・状態・検索結果を1つのストレージで一貫して管理し、運用移行パスを確保するため選択

pgvector

別のベクターDBを追加せず、PostgreSQL内で元のメタデータとベクター検索を一緒に扱うため選択

Notion adapter

Notionを元のストレージとして使うのではなく、必要な場合に知識の断片を外部ワークスペースに同期する境界を示すため選択

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

F
license - not found
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

View all related MCP servers

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.

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

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