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: 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:无需 API 密钥即可运行的确定性演示 embedding provider
indexingPipeline.ts:连接 chunk 生成、embedding 和存储
knowledge.ts:
EmbeddingProvider和VectorRepository端口index.ts:注册
index_note、upsert_vector、search_vectorsMCP 工具
演示 provider 是用于确认流程的确定性实现。它并不是提供基于语义的搜索质量的模型,在实际服务中,可以在同一个 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定义 schema 以与原始 embedding 一起存储
embedding_int8、embedding_scale、embedding_zero_point当前参考搜索使用可恢复的 float 向量,量化 ANN 索引在实际选择 adapter 时添加
实现位于 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 中选择一种。
当前实现是用于确认流程的模拟(mockup)。它不保证基于语义的搜索质量或量化性能,在实际运营中需要接入 embedding provider 和 pgvector adapter。
向量数据库设计
向量存储单元是 NoteChunk。
字段 | 含义 |
| 由原始路径和 chunk 序号生成的标识符 |
| Obsidian Markdown 原始路径 |
| 文档内 chunk 的序号 |
| 作为搜索结果返回的文本 |
| 外部 embedding 模型生成的向量 |
| 标签、状态、原始属性等扩展信息 |
可执行的 SQL 设计示例位于 src/infrastructure/postgres/schema.sql。默认示例使用 1,536 维 embedding 和用于 cosine distance 的 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→ 读取现有 chunk,并同时更新变更字段和量化表示Delete:
delete_chunkSearch:
search_vectors、search_knowledge
当前执行 adapter 是 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_chunksschema 映射PostgreSQL/pgvector schema 和搜索 SQL
Notion 同步边界
Smithery 开发服务器和 Docker 运行示例
当前默认运行是不包含个人数据和外部凭据的内存模拟(memory mockup)。在 PostgreSQL 连接中,将 src/infrastructure/postgres/postgresVectorRepository.ts 中的 Map 实现替换为基于 Drizzle/pg 的 adapter。README 和 schema 是公开展示该转换点的示例。
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:用于 cosine 搜索的 float 向量embedding_int8:为降低存储和传输成本而使用的量化表示
选择 pgvector 的具体原因如下。
数据结合:可以在一条 SQL 中组合向量相似度与
source_path、标签、状态条件一致性:可以在同一事务边界内管理原文元数据和搜索索引
运维简单性:应用程序无需分别运维 PostgreSQL 和独立的向量数据库
搜索功能:可以通过 PostgreSQL 扩展使用 cosine distance(
<=>)和 HNSW 索引扩展路径:初期从单一存储开始,规模扩大时可以分离出搜索专用 adapter
当搜索规模扩大时,专用向量数据库可能更合适。这里的意义在于展示在同一个应用程序边界内处理原文、metadata 和向量搜索的流程。
搜索如何工作
搜索不是直接比较原文字符串,而是将问题和笔记 chunk 放在同一个 embedding 空间中,然后比较距离。
사용자 질문
→ query embedding 생성
→ INT8 양자화 후 복원
→ PostgreSQL/pgvector cosine distance 검색
→ 가까운 NoteChunk 반환
→ sourcePath·content·metadata와 함께 MCP 응답可执行的示例是 search_knowledge MCP 工具。
index_note将 Markdown 拆分为 chunk,并保存每个 chunk 的 embedding。用户发送自然语言
query。使用同一个
EmbeddingProvider生成 query embedding。以与存储向量相同的方式对 query 进行量化和恢复。
VectorRepository.search()根据 cosine similarity 对相近的 chunk 进行排序。搜索结果包含原始路径、chunk 内容、metadata 和 score。
search_vectors 是直接接收已生成 embedding 的低层工具,而 search_knowledge 是从自然语言问题到搜索结果的应用程序级工具。
当前模拟 Repository 在内存 Map 中计算 cosine similarity。切换到 PostgreSQL adapter 后,将在同一个端口后面使用 pgvector 的 <=> 运算和 LIMIT 搜索。
附加技术与投入原因
技术 | 投入原因 |
Node.js ESM | 以当前 Node 运行时方式简单运行 TypeScript MCP 示例 |
MCP SDK | 将 |
Zod | 在运行时验证 MCP 输入值和配置值 |
Drizzle ORM | 在连接 PostgreSQL adapter 时提供类型安全的 schema 和查询边界 |
pg | 切换到实际 PostgreSQL 连接 adapter 时使用的驱动程序 |
Smithery CLI | 提供开发、验证 MCP 服务器的运行路径 |
Docker | 固定本地和部署环境中的 Node/MCP 运行条件 |
chokidar·fast-glob | 负责 Markdown vault 变更检测和文件搜索 |
gray-matter·marked | 将 Markdown frontmatter 和正文作为知识 chunk 处理 |
dotenv | 将本地环境配置与代码分离 |
并非所有依赖项都是向量搜索的核心。有些是用于 Obsidian、Notion 集成的辅助技术,搜索路径的核心是 MCP SDK → Vector Service → Repository → pgvector。
选择技术的原因
技术 | 选择原因 |
Obsidian Markdown | 原文是纯文本文件,所有权和可移植性高,不将知识原文依赖到特定 SaaS |
MCP | 无需为每个 LLM 客户端编写单独的集成代码,以标准接口暴露相同的知识工具 |
TypeScript | 与 MCP SDK 的连接自然,并可用类型管理工具输入、输出边界 |
PostgreSQL | 在单一存储中一致地管理文档元数据、状态和搜索结果,并确保生产转换路径 |
pgvector | 无需添加独立向量数据库,即可在 PostgreSQL 中同时处理原文元数据和向量搜索 |
Notion adapter | 不是为了将 Notion 作为原始存储,而是展示在需要时将知识片段同步到外部工作区的边界 |
Docker | 在本地和部署环境中统一 PostgreSQL、MCP 的运行条件 |
核心不是接入大量工具。原文以 Markdown 保存,搜索用的派生数据放在 PostgreSQL/pgvector 中,仅通过 MCP 向 LLM 提供所需功能。
因此,本项目不是将 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