NoteHarbor MCP
NoteHarbor MCP — TypeScript
Ein TypeScript-Beispiel, das Obsidian-Markdown über MCP-Werkzeuge anbindet und um PostgreSQL/pgvector-Suche erweitert.
NoteHarbor trennt die MCP-Schnittstelle vom Vektorspeicher. Der Client ruft MCP-Werkzeuge auf, und der Service nutzt den Speicher über das Domänenmodell und das Repository.
Architektur
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/)Notizen werden in der folgenden Reihenfolge zu Suchdaten.
Obsidian Markdown
→ note chunk
→ externally generated embedding
→ note_chunks.embedding (pgvector)
→ cosine similarity search
→ MCP responseRelated MCP server: second-brain-mcp
Tatsächlicher Vektorisierungsablauf
upsert_vector ist ein Werkzeug zum Speichern bereits erstellter Embeddings. Den Prozess, wie Markdown in Chunks und Vektoren umgewandelt wird, sehen Sie in index_note.
Markdown text
→ splitMarkdownIntoChunks()
→ EmbeddingProvider.embed(chunk)
→ normalized number[]
→ NoteChunk
→ VectorService.indexChunk()
→ VectorRepository.save()Der Hauptcode ist auf folgende Dateien verteilt:
chunker.ts: Teilt Markdown nach Absätzen und wendet eine maximale Länge an
embeddingProvider.ts: Deterministischer Demo-Embedding-Provider, der ohne API-Schlüssel funktioniert
indexingPipeline.ts: Verbindet Chunk-Erstellung, Embedding und Speicherung
knowledge.ts: Ports für
EmbeddingProviderundVectorRepositoryindex.ts: Registriert die MCP-Werkzeuge
index_note,upsert_vector,search_vectors
Der Demo-Provider ist eine deterministische Implementierung, um den Ablauf zu veranschaulichen. Er bietet keine semantische Suchqualität; in einem echten Dienst wird derselbe EmbeddingProvider-Port mit einem externen oder lokalen Modell verbunden.
Die Quantisierung wird nach der Embedding-Erzeugung angewendet.
float embedding [-1, 1]
→ clamp
→ int8 = round(value / (1 / 127))
→ 저장: values + scale + zeroPoint
→ 복원: (int8 - zeroPoint) * scaleDas Beispiel verwendet symmetrische skalare INT8-Quantisierung.
Wertebereich:
[-1, 1]Quantisierungsbereich:
[-127, 127]scale:1 / 127zeroPoint:0Das Schema speichert
embedding_int8,embedding_scaleundembedding_zero_pointzusammen mit dem ursprünglichen EmbeddingDie aktuelle Referenzsuche verwendet wiederherstellbare Float-Vektoren; ein quantisierter ANN-Index wird bei der Auswahl eines echten Adapters hinzugefügt
Die Implementierung befindet sich in quantizer.ts und indexingPipeline.ts. Die Antwort von index_note enthält auch die Embedding-Dimension und die Anzahl der Quantisierungsbits.
Warum diese Struktur?
NoteHarbor ist ein Beispiel, das Obsidian-Markdown in durchsuchbare Wissenseinheiten umwandelt und diese Funktionen als MCP-Werkzeuge bereitstellt.
Mit einfacher String-Suche lassen sich verwandte Inhalte mit anderer Formulierung schwer finden. Deshalb werden Notizen in kleine Chunks zerlegt und jeder Chunk in ein Embedding umgewandelt, sodass nach inhaltlich ähnlichen Inhalten gesucht werden kann.
Die Quantisierung ist eine Option, um diese Embeddings kompakter zu speichern.
Reduziert Speicher und Speicherplatz
Reduziert die Datenmenge bei der Vektorübertragung
Vorteilhaft für Cache und Batch-Verarbeitung in großen Wissensdatenbanken
Dafür kann die Präzision geringer sein als beim ursprünglichen Float
Daher wurden die Rollen der Komponenten wie folgt aufgeteilt:
Embedding: Drückt die Bedeutung von Text als numerischen Vektor aus
Quantisierung: Reduziert die Speicherkosten durch geringere Präzision der Vektoren
Vektorsuche: Findet nahe Vektoren und gibt relevante Chunks zurück
MCP: Stellt diese Funktionen als Werkzeuge für LLM-Clients bereit
Die Wahl von INT8 in diesem Projekt liegt daran, dass sich das Quantisierungsprinzip und die Speicherform leicht im Code erklären lassen. In einem echten Dienst sollten Sie nach Messung von Suchqualität, Speicherersparnis und Latenz zwischen float32, float16, INT8 und binary wählen.
Die aktuelle Implementierung ist ein Mockup, um den Ablauf zu veranschaulichen. Sie garantiert weder semantische Suchqualität noch Quantisierungsleistung; im Produktivbetrieb müssen ein Embedding-Provider und ein pgvector-Adapter angebunden werden.
Vektor-DB-Design
Die Vektorspeichereinheit ist NoteChunk.
Feld | Bedeutung |
| Identifikator aus Quellpfad und Chunk-Reihenfolge |
| Quellpfad des Obsidian-Markdown |
| Reihenfolge des Chunks im Dokument |
| Text, der als Suchergebnis zurückgegeben wird |
| Vektor, der von einem externen Embedding-Modell erzeugt wurde |
| Erweiterte Informationen wie Tags, Status, Quellattribute |
Ein ausführbares SQL-Designbeispiel finden Sie in src/infrastructure/postgres/schema.sql. Das Standardbeispiel verwendet ein 1.536-dimensionales Embedding und einen HNSW-Index für die Kosinus-Distanz; es wird an die Dimension des tatsächlichen Embedding-Modells angepasst.
Die Suche wird in PostgreSQL wie folgt umgesetzt:
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- und ORM-Stil-Grenzen
Der Vektorspeicher ist kein reiner Suchspeicher, sondern ein Repository, das den Lebenszyklus von NoteChunk verwaltet.
Create/Upsert:
upsert_vector,index_note→VectorService.indexChunk()Read:
get_chunk,list_chunksUpdate:
update_chunk→ liest den vorhandenen Chunk und aktualisiert geänderte Felder sowie die quantisierte DarstellungDelete:
delete_chunkSearch:
search_vectors,search_knowledge
Der aktuelle Ausführungsadapter ist eine Map. In einer Produktionsumgebung ersetzen Sie die Implementierung im Repository durch Drizzle ORM und 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-Werkzeuge führen kein SQL direkt aus, sondern übergeben CRUD und Suche in der Reihenfolge MCP → VectorService → VectorRepository → Drizzle/pgvector.
Enthaltene Beispiele
Obsidian-Markdown auflisten, lesen, durchsuchen
MCP-Werkzeuge
index_note,search_knowledge,upsert_vector,search_vectorsSchicht
MCP → Service → Repository → pgvectorDrizzle-ORM-basierte Zuordnung des
note_chunks-SchemasPostgreSQL/pgvector-Schema und Such-SQL
Notion-Synchronisationsgrenze
Beispiele für Smithery-Entwicklungsserver und Docker-Ausführung
Die aktuelle Standardausführung ist ein In-Memory-Mockup, das keine persönlichen Daten und keine externen Anmeldeinformationen enthält. Bei einer PostgreSQL-Verbindung wird die Map-Implementierung in src/infrastructure/postgres/postgresVectorRepository.ts durch einen Drizzle/pg-basierten Adapter ersetzt. README und Schema sind Beispiele, um diesen Übergangspunkt öffentlich zu zeigen.
Die Python/GraphQL-Version finden Sie unter noteharbor-python.
Erste Schritte
npm install
npm run devDocker:
docker build -f Dockerfile.typescript -t noteharbor-mcp-ts .
docker run --rm -p 8081:8081 noteharbor-mcp-tsWarum PostgreSQL + pgvector?
Die Suchziele von NoteHarbor sind nicht nur Vektordaten. Es müssen auch relationale Metadaten wie Quellpfad, Chunk-Reihenfolge, Tags, Status und Synchronisationsinformationen verarbeitet werden.
Deshalb werden in diesem Beispiel keine separate Vektor-DB, sondern folgende Daten in PostgreSQL abgelegt:
content: Originaltextfragment, das als Suchergebnis angezeigt wirdmetadata: Tags, Status, Quellinformationenembedding: Float-Vektor für die Kosinus-Sucheembedding_int8: Quantisierte Darstellung zur Reduzierung von Speicher- und Übertragungskosten
Die konkreten Gründe für pgvector sind:
Datenkombination: Vektorähnlichkeit und Bedingungen wie
source_path, Tags und Status lassen sich in einem SQL kombinierenKonsistenz: Originalmetadaten und Suchindex können in derselben Transaktionsgrenze verwaltet werden
Betriebliche Einfachheit: Die Anwendung muss nicht PostgreSQL und eine separate Vektor-DB betreiben
Suchfunktionen: Kosinus-Distanz (
<=>) und HNSW-Index sind als PostgreSQL-Erweiterung verfügbarSkalierungspfad: Zunächst mit einem einzigen Speicher beginnen und bei wachsendem Umfang einen suchspezifischen Adapter ausgliedern
Bei sehr großem Suchumfang kann eine dedizierte Vektor-DB besser geeignet sein. Hier geht es darum, den Ablauf zu zeigen, bei dem Originaltext, Metadaten und Vektorsuche in einer Anwendungsgrenze behandelt werden.
Wie funktioniert die Suche?
Die Suche vergleicht nicht direkt die Originaltextzeichenfolgen, sondern legt Frage und Notiz-Chunks in denselben Embedding-Raum und vergleicht dann die Distanzen.
사용자 질문
→ query embedding 생성
→ INT8 양자화 후 복원
→ PostgreSQL/pgvector cosine distance 검색
→ 가까운 NoteChunk 반환
→ sourcePath·content·metadata와 함께 MCP 응답Ein ausführbares Beispiel ist das MCP-Werkzeug search_knowledge.
index_noteteilt Markdown in Chunks und speichert das Embedding jedes Chunks.Der Benutzer sendet eine natürliche Sprachabfrage
query.Mit demselben
EmbeddingProviderwird ein Query-Embedding erzeugt.Die Query wird wie die gespeicherten Vektoren quantisiert und wiederhergestellt.
VectorRepository.search()sortiert die nahen Chunks nach Kosinus-Ähnlichkeit.Die Suchergebnisse enthalten Quellpfad, Chunk-Inhalt, Metadaten und Score.
search_vectors ist ein Low-Level-Werkzeug, das direkt ein bereits erstelltes Embedding entgegennimmt, während search_knowledge ein Anwendungswerkzeug ist, das von der natürlichen Sprachfrage bis zum Suchergebnis verbindet.
Das aktuelle Mockup-Repository berechnet die Kosinus-Ähnlichkeit in einer In-Memory-Map. Nach der Umstellung auf den PostgreSQL-Adapter werden hinter demselben Port die <=>-Operation und LIMIT-Suche von pgvector verwendet.
Zusätzliche Technologien und Gründe für ihren Einsatz
Technologie | Grund für den Einsatz |
Node.js ESM | Um das TypeScript-MCP-Beispiel einfach mit der aktuellen Node-Laufzeit auszuführen |
MCP SDK | Um die Werkzeuge |
Zod | Zur Laufzeitvalidierung von MCP-Eingaben und Konfigurationswerten |
Drizzle ORM | Bietet typsichere Schema- und Query-Grenzen beim Anbinden des PostgreSQL-Adapters |
pg | Treiber für die Umstellung auf einen echten PostgreSQL-Verbindungsadapter |
Smithery CLI | Bietet einen Ausführungspfad zum Entwickeln und Validieren des MCP-Servers |
Docker | Fixiert die Node/MCP-Ausführungsbedingungen in lokalen und Bereitstellungsumgebungen |
chokidar·fast-glob | Zuständig für die Erkennung von Änderungen im Markdown-Vault und die Dateisuche |
gray-matter·marked | Behandelt Markdown-Frontmatter und -Text als Wissens-Chunks |
dotenv | Trennt lokale Umgebungseinstellungen vom Code |
Nicht alle Abhängigkeiten sind für die Vektorsuche zentral. Einige sind Hilfstechnologien für die Obsidian- und Notion-Integration; der Kern des Suchpfads ist MCP SDK → Vector Service → Repository → pgvector.
Gründe für die Technologiewahl
Technologie | Auswahlgrund |
Obsidian Markdown | Gewählt, weil die Originale als Klartextdateien vorliegen, was Eigentum und Portabilität erhöht und das Wissensoriginal nicht an eine bestimmte SaaS bindet |
MCP | Gewählt, um dieselben Wissenswerkzeuge über eine Standardschnittstelle bereitzustellen, ohne für jeden LLM-Client separate Integrationscodes zu schreiben |
TypeScript | Gewählt, weil die Verbindung zum MCP SDK natürlich ist und die Ein-/Ausgabegrenzen der Werkzeuge typisiert verwaltet werden |
PostgreSQL | Gewählt, um Dokumentmetadaten, Status und Suchergebnisse konsistent in einem Speicher zu verwalten und einen Produktionsübergangspfad zu sichern |
pgvector | Gewählt, um Originalmetadaten und Vektorsuche in PostgreSQL zu behandeln, ohne eine separate Vektor-DB hinzuzufügen |
Notion-Adapter | Gewählt, um eine Grenze zu zeigen, die Wissensfragmente bei Bedarf in einen externen Workspace synchronisiert, statt Notion als Originalspeicher zu verwenden |
Docker | Gewählt, um die PostgreSQL- und MCP-Ausführungsbedingungen in lokalen und Bereitstellungsumgebungen einheitlich zu gestalten |
Der Kern liegt nicht darin, viele Werkzeuge anzubinden. Es geht darum, die Originale als Markdown zu bewahren, abgeleitete Suchdaten in PostgreSQL/pgvector zu halten und dem LLM nur die benötigten Funktionen über MCP bereitzustellen.
Daher ist dieses Projekt kein System, das Obsidian, Notion und PostgreSQL alle als Originalquellen verwendet.
Obsidian-Markdown: Originalwissen
PostgreSQL/pgvector: Abgeleiteter Suchindex
Notion: Optionales externes Synchronisationsziel
MCP: Zugriffsgrenze für LLMs
Design-Punkte
Bewahrung des Original-Markdowns
Trennung von MCP-Werkzeugen und Service-Schicht
NoteChunk-Domänenmodell undVectorRepository-PortAustauschbare Speichergrenze mit PostgreSQL/pgvector
Ausschluss von echten persönlichen Vaults und Anmeldeinformationen
Dieses Projekt ist ein öffentliches Beispiel, um die Struktur von MCP und Wissenssuche zu veranschaulichen.
Lizenz
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