NoteHarbor MCP
NoteHarbor MCP
一个 Python 示例,用于通过 MCP 和 GraphQL 查询 Obsidian 笔记,并使用 PostgreSQL/pgvector 进行扩展。不包含个人 vault、真实文档和 API 密钥。
NoteHarbor 的原始形态是 Markdown 文件。仅为搜索所需的数据单独创建内容,原始文件则原样保留。
本项目的准则
本地优先(Local first):原始 Markdown 保留在本地,外部服务仅作为可连接的选项。
保留源文件(Source preserving):搜索、嵌入、同步的结果不会取代原始内容。
边界隐私(Privacy by boundary):实际 vault、个人记录和 API 密钥均保留在公开项目之外。
模型中立(Model neutral):不将 embedding 生成器和 Vector DB 绑定到特定厂商。
小而可替换(Small and replaceable):保持适配器和服务层足够小。
Related MCP server: Notes RAG MCP Server
三个公开示例
MCP:
upsert_vector、search_vectors工具GraphQL:
indexChunkMutation、vectorSearchQueryPostgreSQL/pgvector:SQLAlchemy 模型、Repository 端口、Docker 开发环境
它是用于确认结构而非生产服务的示例。默认 Repository 在内存中运行,并同时提供了迁移到 PostgreSQL/pgvector 的切入点与 SQL 示例。
快速开始
uv sync运行 MCP 示例:
uv run noteharbor用 Docker 启动 PostgreSQL
docker compose up -d postgresdocker-compose.yml 定义了 pgvector/pgvector 镜像和用于 Python MCP 的开发用 PostgreSQL。
# PostgreSQL만
docker compose up -d postgres
# Python MCP까지
docker compose up --build python-mcpPOSTGRES_URL 是接入真实数据库连接时使用的配置占位。当前默认执行为 mock。
GraphQL 示例
GraphQL schema 位于 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
当前适配器是用于确认功能正常的内存储模拟实现。实际存储方式放在 SQLAlchemy ORM 边界之后。在真实 PostgreSQL 适配器中,将用如下会话操作来替换 MockPostgresVectorRepository。
如果想看真实 ORM 流程的代码,可以查看 noteharbor/infrastructure/postgres/sqlalchemy_repository.py。该适配器实现了相同的 VectorRepository 端口,并使用 Session.get、select、update、delete。默认执行为基于 mock,因此无需连接 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,而是按照 MCP/GraphQL → VectorService → VectorRepository → SQLAlchemy/pgvector 的顺序传递 CRUD 和检索。
目的
本仓库是一个 Python 架构示例,展示同一个 Markdown 源文件如何通过 MCP 和 GraphQL 两侧由同一个向量检索服务进行查询。
与其预先固定某个特定 embedding 厂商或某个特定向量数据库,更注重于明确标注出可替换的切入点。
MCP / GraphQL API
→ VectorService
→ VectorRepository port
→ 현재: in-memory MockPostgresVectorRepository
→ 전환: PostgreSQL + pgvector向量化与检索的职责
当前 Python 示例不会直接生成 embedding。由 indexChunk mutation 和 upsert_vector 工具接收外部生成的 list[float] embedding 保存。
将 embedding 生成分开的原因如下:
为了不将 embedding 模型固定为 OpenAI、Voyage 或本地模型之一
为了排除 API 密钥和个人数据不进入公开示例
为了分离 API 层与检索存储的职责
为了在实际服务中把 chunking·embedding 批处理流水线替换为独立 worker
检索按以下顺序进行:
사용자 query embedding
→ GraphQL vectorSearch 또는 MCP search_vectors
→ VectorService.search()
→ Repository.search()
→ cosine similarity 계산
→ score가 높은 NoteChunk 반환目前 repository.py 中的 MockPostgresVectorRepository 在内存中再现此流程。真实 PostgreSQL 适配器使用 embedding <=> :query_embedding 计算余弦距离,并以 1 - distance 作为 score 返回。
为什么选择 PostgreSQL + pgvector
NoteChunk 不只是包含向量的值,还同时具有原始路径、chunk 序号、正文和元数据。将 PostgreSQL 与 pgvector 结合,可以在同一个存储库与 SQL 边界内处理关系型条件和向量相似度检索。
PostgreSQL:原始元数据、状态、同步信息和事务管理
pgvector:
vector列、余弦距离(<=>)、HNSW 索引Docker:在开发环境中固定 pgvector 的运行条件
SQLAlchemy Repository:替换存储的切入点
检索规模扩大时,专用向量数据库可能更合适。这里展示的是在同一个存储中处理文档信息与向量检索的流程。
量化的范围
当前的 Python 仓库中尚未加入量化实现。输入 embedding 以 float 值原样接收并检索,这是为了优先展示模型中性的 Repository 边界。
如需加入量化,会单独设置 EmbeddingQuantizer 端口,并由 float32 → INT8/float16 → 存储与恢复 放置于 indexing worker 与 Repository adapter 之间。由于量化方式必须在搜索质量、内存和延迟时间测量后再确定,因此本示例并不夸张地声称已经实现。
两个 NoteHarbor 示例的关系
noteharbor-mcp :TypeScript MCP 工具和 embedding、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 | 用于在 Python 中处理 PostgreSQL 连接 |
pgvector Python package | 用于以 SQLAlchemy 模型表示 PostgreSQL 的 vector 类型 |
Strawberry GraphQL | 提供将同一个 VectorService 暴露为 GraphQL Query/Mutation 的示例 |
**postgreSQL ** | 用于复现已启用 pgvector 的 PostgreSQL 与 Python 开发环境 |
每种技术都按 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 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 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 gradedqualityBmaintenanceEnables semantic search over personal markdown notes by indexing them into a vector database and exposing search, reindex, and status tools via MCP.
- AlicenseNot gradedqualityBmaintenanceIndexes local Markdown/text files into a SQLite database with vector embeddings and provides MCP tools for semantic search without cloud dependencies.GPL 3.0
- AlicenseNot gradedqualityAmaintenanceProvides MCP tools for semantic search over personal knowledge sources using pluggable embeddings and local vector indexing.1MIT
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.
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-python'
If you have feedback or need assistance with the MCP directory API, please join our Discord server