NoteHarbor MCP
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 responseRelated MCP server: Smart Connections MCP Server
実際のベクトル化フロー
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:
EmbeddingProviderとVectorRepositoryのポートindex.ts:
index_note、upsert_vector、search_vectorsMCPツールを登録
デモプロバイダーはフローを確認するための決定的な実装です。意味ベースの検索品質を提供するモデルではなく、実際のサービスでは同じ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とともに
embedding_int8、embedding_scale、embedding_zero_pointを保存するようにスキーマを定義現在の参照検索は復元可能なfloatベクターを使用し、量子化ANNインデックスは実際のアダプター選択時に追加
実装はquantizer.tsとindexingPipeline.tsにあります。index_note応答にもEmbedding次元と量子化ビット数が含まれます。
なぜこのように構成したのか
NoteHarborはObsidian Markdownを検索可能な知識単位に変換し、その機能をMCPツールとして提供する例です。
単純な文字列検索だけでは、表現が異なる関連内容を見つけるのは困難です。そこでノートを小さなチャンクに分割し、各チャンクをEmbeddingに変換して意味が近い内容を検索できるようにします。
量子化はこのEmbeddingをより小さな表現で保持するための選択です。
メモリとストレージ容量を削減
ベクター転送量を削減
大規模ナレッジベースでキャッシュとバッチ処理に有利
代わりに元のfloatより精度が低くなる可能性がある
そこで、各構成要素の役割を次のように分けました。
Embedding: テキストの意味を数値ベクターで表現
Quantization: ベクターの精度を下げて保存コストを削減
Vector search: 近いベクターを見つけて関連チャンクを返す
MCP: この機能をLLMクライアントが呼び出せるツールとして公開
このプロジェクトでINT8を選択した理由は、量子化の原理と保存形式をコードで説明しやすいからです。実際のサービスでは、検索品質・メモリ削減・レイテンシーを測定した後、float32・float16・INT8・binaryのいずれかを選択する必要があります。
現在の実装はフローを確認するためのモックアップです。意味ベースの検索品質や量子化パフォーマンスを保証するものではなく、実際の運用ではEmbeddingプロバイダーとpgvectorアダプターを接続する必要があります。
ベクターDB設計
ベクター保存単位はNoteChunkです。
フィールド | 意味 |
| 元のパスとチャンク順序で作成した識別子 |
| Obsidian Markdownの元のパス |
| ドキュメント内のチャンク順序 |
| 検索結果として返すテキスト |
| 外部Embeddingモデルが生成したベクター |
| タグ・ステータス・元の属性などの拡張情報 |
実行可能な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_vector、index_note→VectorService.indexChunk()Read:
get_chunk、list_chunksUpdate:
update_chunk→ 既存のチャンクを読み取り、変更フィールドと量子化表現を一緒に更新Delete:
delete_chunkSearch:
search_vectors、search_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_note、search_knowledge、upsert_vector、search_vectorsMCPツールMCP → Service → Repository → pgvector階層Drizzle ORMベースの
note_chunksスキーママッピングPostgreSQL/pgvectorスキーマと検索SQL
Notion同期境界
Smithery開発サーバーとDocker実行例
現在のデフォルト実行は、個人データと外部資格情報を含まないメモリモックアップです。PostgreSQL接続では、src/infrastructure/postgres/postgresVectorRepository.tsのMap実装を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の検索対象はベクターだけのデータではありません。元のパス、チャンク順序、タグ、状態、同期情報などのリレーショナルメタデータを一緒に扱う必要があります。
そこで、このサンプルでは別のベクター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ツールです。
index_noteがMarkdownをチャンクに分割し、各チャンクのEmbeddingを保存します。ユーザーが自然言語
queryを送信します。同じ
EmbeddingProviderでクエリEmbeddingを生成します。クエリを保存ベクターと同じ方法で量子化・復元します。
VectorRepository.search()がコサイン類似度基準で近いチャンクをソートします。検索結果には元のパス、チャンク内容、メタデータ、スコアが含まれます。
search_vectorsはすでに作成されたEmbeddingを直接受け取る低レベルツールで、search_knowledgeは自然言語の質問から検索結果までを接続するアプリケーションレベルのツールです。
現在のモックRepositoryはメモリ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 | 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
This server cannot be deployed
Maintenance
Related MCP Connectors
Personal knowledge base MCP server with semantic search, auto-categorization, metadata extraction
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.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceConnects AI assistants to an Obsidian vault as a semantic knowledge graph, enabling graph navigation, semantic search, and content operations through MCP.9 npm467MIT
- FlicenseNot gradedqualityDmaintenanceEnables semantic search and related-note discovery across an Obsidian vault via MCP, providing RAG context blocks for natural language queries.-
- FlicenseAqualityCmaintenanceExposes Obsidian notes as a semantic search and RAG knowledge base over MCP, enabling AI assistants to index, retrieve, and analyze personal notes via natural language.71-
- AlicenseBqualityAmaintenanceEnables local hybrid search over Obsidian and Markdown vaults via MCP, combining vector retrieval, full-text search, reranking, graph navigation, and safe CRUD while keeping data local.431MIT