Skip to main content
Glama

NoteHarbor MCP — TypeScript

Ejemplo en TypeScript que conecta Obsidian Markdown con herramientas MCP y lo extiende con búsqueda PostgreSQL/pgvector.

NoteHarbor separa la interfaz MCP del almacén vectorial. El cliente invoca las herramientas MCP y el servicio utiliza el modelo de dominio y el repositorio para acceder al almacén.

Arquitectura

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/)

Las notas se convierten en datos de búsqueda en el siguiente orden.

Obsidian Markdown
  → note chunk
  → externally generated embedding
  → note_chunks.embedding (pgvector)
  → cosine similarity search
  → MCP response

Related MCP server: second-brain-mcp

Flujo real de vectorización

upsert_vector es la herramienta que guarda un embedding ya creado. El proceso de transformar Markdown en chunks y vectores se puede ver en index_note.

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

El código principal está dividido en los siguientes archivos.

  • chunker.ts: divide el Markdown por párrafos y aplica la longitud máxima

  • embeddingProvider.ts: proveedor de embedding determinista que funciona sin clave de API

  • indexingPipeline.ts: conecta la generación de chunks, embeddings y el guardado

  • knowledge.ts: puertos EmbeddingProvider y VectorRepository

  • index.ts: registro de las herramientas MCP index_note, upsert_vector, search_vectors

El proveedor de demostración es una implementación determinista para verificar el flujo. No ofrece calidad de búsqueda semántica; en un servicio real se conecta un modelo externo o local al mismo puerto EmbeddingProvider.

La cuantización se aplica después de generar el embedding.

float embedding [-1, 1]
  → clamp
  → int8 = round(value / (1 / 127))
  → 저장: values + scale + zeroPoint
  → 복원: (int8 - zeroPoint) * scale

La muestra utiliza cuantización escalar simétrica INT8.

  • Valores: [-1, 1]

  • Rango de cuantización: [-127, 127]

  • scale: 1 / 127

  • zeroPoint: 0

  • El esquema guarda embedding_int8, embedding_scale, embedding_zero_point junto con el embedding original

  • La búsqueda de referencia actual usa el vector float restaurado; el índice ANN cuantizado se añade al elegir el adaptador real

La implementación está en quantizer.ts y indexingPipeline.ts. La respuesta de index_note también incluye la dimensión del embedding y el número de bits de cuantización.

Por qué está estructurado así

NoteHarbor es un ejemplo que convierte Obsidian Markdown en unidades de conocimiento buscables y expone esa funcionalidad como herramientas MCP.

Con la búsqueda de cadenas simple es difícil encontrar contenido relacionado expresado de otra forma. Por eso las notas se dividen en chunks pequeños y cada chunk se transforma en un embedding para poder buscar por cercanía semántica.

La cuantización sirve para guardar ese embedding en una representación más compacta.

  • Reduce el uso de memoria y almacenamiento

  • Reduce el volumen de transferencia de vectores

  • Favorece la caché y el procesamiento por lotes en bases de conocimiento grandes

  • A cambio, la precisión puede ser ligeramente menor que con float original

Por eso el rol de cada componente es el siguiente.

  1. Embedding: representa el significado del texto como un vector numérico

  2. Quantization: reduce la precisión del vector para disminuir el costo de almacenamiento

  3. Vector search: encuentra los chunks cercanos comparando vectores

  4. MCP: expone esta funcionalidad como una herramienta que los clientes LLM pueden invocar

En este proyecto se eligió INT8 porque es fácil de explicar el principio de cuantización y la implementación de demostración. En un servicio real se debe medir calidad de búsqueda, ahorro de memoria, latencia y elegir entre float32, float16, INT8 o binary.

La implementación actual es un simulacro para verificar el flujo. No garantiza calidad de búsqueda semántica ni rendimiento de cuantización; en producción se debe conectar un proveedor de embeddings real y un adaptador pgvector.

Diseño de la base de datos vectorial

La unidad de almacenamiento vectorial es NoteChunk.

Campo

Significado

id

Identificador formado por la ruta original y el número de chunk

sourcePath

Ruta original del Markdown de Obsidian

chunkIndex

Número de chunk dentro del documento

content

Texto que se devuelve como resultado de búsqueda

embedding

Vector generado por el modelo de embeddings

metadata

Extensión con etiquetas, estado, atributos del origen

El ejemplo de SQL ejecutable está en src/infrastructure/postgres/schema.sql. El ejemplo básico usa un embedding de 1536 dimensiones y un índice HNSW para distancia coseno; se ajusta según la dimensión del modelo real.

La búsqueda se transforma en la siguiente forma en 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;

Límite entre CRUD y estilo ORM

El almacén vectorial no es solo para búsqueda; es un repositorio que gestiona el ciclo de vida completo de NoteChunk.

  • Create/Upsert: upsert_vector, index_noteVectorService.indexChunk()

  • Read: get_chunk, list_chunks

  • Update: update_chunk → lee el chunk existente y actualiza el campo modificado y la representación cuantizada

  • Delete: delete_chunk

  • Search: search_vectors, search_knowledge

El adaptador de ejecución actual es un Map en memoria. En un entorno de producción se reemplaza la implementación interna del repositorio por Drizzle ORM y 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))

Las herramientas MCP no ejecutan SQL directamente; delegan en MCP → VectorService → VectorRepository → Drizzle/pgvector para las operaciones CRUD y búsqueda.

Ejemplos incluidos

  • Listado, lectura y búsqueda de Markdown de Obsidian

  • Herramientas MCP index_note, search_knowledge, upsert_vector, search_vectors

  • Capas MCP → Service → Repository → pgvector

  • Esquema note_chunks basado en Drizzle ORM

  • Esquema PostgreSQL/pgvector y SQL de búsqueda

  • Límite de sincronización con Notion

  • Servidor de desarrollo Smithery y ejemplo de ejecución con Docker

La ejecución básica actual es un simulacro en memoria que no incluye datos personales ni credenciales externas. En la conexión PostgreSQL, la implementación Map de src/infrastructure/postgres/postgresVectorRepository.ts se reemplaza por un adaptador basado en Drizzle/pg. El README y el esquema son una muestra pública del punto de transición.

La versión Python/GraphQL está disponible en noteharbor-python.

Comenzar

npm install
npm run dev

Docker:

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

Por qué PostgreSQL + pgvector

El objetivo de búsqueda de NoteHarbor no son solo datos vectoriales. También hay que gestionar metadatos relacionales como la ruta original, el número de chunk, las etiquetas, el estado y la información de sincronización.

Por eso, en lugar de añadir una base de datos vectorial separada, este ejemplo mantiene todo junto en PostgreSQL.

  • content: fragmento de texto original que se muestra como resultado de búsqueda

  • metadata: etiquetas, estado e información del origen

  • embedding: vector float para búsqueda por coseno

  • embedding_int8: representación cuantizada para reducir costo de almacenamiento y transferencia

Las razones concretas para elegir pgvector son las siguientes.

  • Combinación de datos: se puede combinar similitud vectorial con source_path, etiquetas y condiciones de estado en una sola SQL

  • Consistencia: los metadatos del texto original y el índice de búsqueda se gestionan dentro del mismo límite de transacción

  • Simplicidad operativa: la aplicación no necesita operar PostgreSQL y una base vectorial separada por separado

  • Funcionalidad de búsqueda: se puede usar distancia coseno (<=>) e índice HNSW como extensión de PostgreSQL

  • Camino de escalado: se comienza con un solo almacén y, cuando crece la escala, se puede separar un adaptador exclusivo de búsqueda

Cuando la escala de búsqueda crece, una base vectorial dedicada puede ser más adecuada. Aquí el valor está en mostrar el flujo que maneja texto original, metadatos y búsqueda vectorial dentro de un mismo límite de aplicación.

Cómo funciona la búsqueda

La búsqueda no compara directamente las cadenas del texto original; coloca la pregunta y los chunks de las notas en el mismo espacio de embeddings y compara distancias.

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

La muestra ejecutable es la herramienta MCP search_knowledge.

  1. index_note divide el Markdown en chunks y guarda el embedding de cada chunk.

  2. El usuario envía una query en lenguaje natural.

  3. Se genera el embedding de la consulta con el mismo EmbeddingProvider.

  4. La consulta se cuantiza y restaura de la misma forma que los vectores guardados.

  5. VectorRepository.search() ordena los chunks cercanos según similitud coseno.

  6. El resultado incluye la ruta original, el contenido del chunk, los metadatos y la puntuación.

search_vectors es una herramienta de bajo nivel que recibe directamente un embedding ya creado; search_knowledge es una herramienta de nivel de aplicación que conecta desde la pregunta en lenguaje natural hasta el resultado de búsqueda.

El repositorio simulado actual calcula la similitud coseno en un Map en memoria. Al migrar al adaptador PostgreSQL, se usará la operación <=> de pgvector y la búsqueda con LIMIT detrás del mismo puerto.

Tecnologías adicionales y motivo de su uso

Tecnología

Motivo de su uso

Node.js ESM

Ejecutar el ejemplo TypeScript MCP de forma sencilla con el runtime Node actual

MCP SDK

Registrar las herramientas index_note, search_knowledge, upsert_vector, search_vectors como servidor MCP estándar

Zod

Validar en runtime las entradas MCP y los valores de configuración

Drizzle ORM

Proporcionar un límite de esquema y consultas con seguridad de tipos al conectar el adaptador PostgreSQL

pg

Driver que se usará al migrar al adaptador de conexión PostgreSQL real

Smithery CLI

Proporcionar una ruta de ejecución para desarrollar y verificar el servidor MCP

Docker

Fijar las condiciones de ejecución de Node/MCP en entornos locales y de despliegue

chokidar·fast-glob

Detección de cambios en el vault de Markdown y exploración de archivos

gray-matter·marked

Tratar el frontmatter y el cuerpo del Markdown como chunks de conocimiento

dotenv

Separar la configuración local del entorno del código

No todas las dependencias son el núcleo de la búsqueda vectorial. Algunas son tecnologías auxiliares para la integración con Obsidian y Notion; el centro de la ruta de búsqueda es MCP SDK → Vector Service → Repository → pgvector.

Razones para elegir cada tecnología

Tecnología

Razón de la elección

Obsidian Markdown

El original es un archivo de texto plano, por lo que la propiedad y la portabilidad son altas; se evita depender de un SaaS concreto para el conocimiento original

MCP

No crear código de integración separado para cada cliente LLM; exponer la misma herramienta de conocimiento con una interfaz estándar

TypeScript

La conexión con el MCP SDK es natural y los límites de entrada y salida de las herramientas se gestionan con tipos

PostgreSQL

Gestionar metadatos de documentos, estado y resultados de búsqueda de forma coherente en un solo almacén y asegurar una ruta de migración a producción

pgvector

Sin añadir una base vectorial separada, manejar metadatos del texto original y búsqueda vectorial juntos dentro de PostgreSQL

Adaptador Notion

Más que usar Notion como almacén original, mostrar el límite para sincronizar fragmentos de conocimiento con un workspace externo cuando sea necesario

Docker

Mantener uniformes las condiciones de ejecución de PostgreSQL y MCP entre el entorno local y el de despliegue

El núcleo no es añadir muchas herramientas. Preservar el original como Markdown, poner los datos derivados de búsqueda en PostgreSQL/pgvector y ofrecer al LLM solo las funciones necesarias a través de MCP.

Por lo tanto, este proyecto no es un sistema que use Obsidian, Notion y PostgreSQL todos como fuentes originales.

  • Obsidian Markdown: conocimiento original

  • PostgreSQL/pgvector: índice derivado para búsqueda

  • Notion: destino opcional de sincronización externa

  • MCP: límite de acceso del LLM

Puntos de diseño

  • Preservación del Markdown original

  • Separación entre herramientas MCP y capa de servicios

  • Modelo de dominio NoteChunk y puerto VectorRepository

  • Límite de almacenamiento reemplazable por PostgreSQL/pgvector

  • Exclusión del vault personal real y las credenciales

Este proyecto es un ejemplo público para verificar la estructura de MCP y la búsqueda de conocimiento.

Licencia

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