Obsidian Hybrid Search

Servidor MCP local-first para buscar en bóvedas privadas de Obsidian con recuperación híbrida de texto completo, difusa, semántica y de grafos de wikilinks.

Documentación

Obsidian Hybrid Search

npm version Tests Total downloads

Obsidian Hybrid Search explains hybrid retrieval from Obsidian notes

Tu bóveda de Obsidian ya contiene tu mejor pensamiento. Obsidian Hybrid Search hace que ese pensamiento sea más fácil de encontrar, reutilizar e incorporar al trabajo asistido por IA.

Le da a tu bóveda un motor de recuperación y tres formas prácticas de usarlo. El plugin nativo de Obsidian te ofrece búsqueda rápida, vistas previas, notas similares, descubrimiento de enlaces y vistas de grafo mientras escribes. El servidor MCP permite que los agentes de IA busquen y lean tus notas como llamadas a herramientas. La CLI les da a los usuarios avanzados el mismo motor para indexar, filtrar, reordenar, leer y escribir scripts.

La búsqueda entiende cómo se construyen las bóvedas reales. Combina búsqueda semántica, texto completo BM25, coincidencia difusa de títulos y alias, etiquetas, carpetas, frontmatter, wikilinks, backlinks y búsqueda de notas similares. Puedes buscar por idea, frase, título, relación o metadatos sin recordar las palabras exactas que escribiste.

Eso convierte a Obsidian en un sistema de conocimiento personal más sólido y en un mejor punto de partida para el trabajo con IA. Los agentes pueden comenzar desde tus propias notas, extraer contexto citado de archivos fuente, seguir material relacionado y trabajar con conocimiento que ya confías. OHS se ejecuta localmente por defecto con SQLite, FTS5, sqlite-vec, clasificación RRF y APIs de incrustación opcionales compatibles con OpenAI.

Calidad de búsqueda

Evaluado en la bóveda de ayuda de Obsidian (171 notas, 58 consultas, modelo local):

OHS (este proyecto)qmd
nDCG@50.7330.659
MRR0.7880.665
Hit@10.7240.500
Tiempo promedio de consulta571 ms ¹754 ms ²
Descarga del modelo~117 MB~2.2 GB

¹ CPU (Apple Silicon), modo híbrido, sin reordenamiento. ² GPU (Apple Silicon Metal), expansión de consulta LLM + reordenamiento.

OHS usa Xenova/multilingual-e5-small. Cómo reproducir → · Benchmark completo →

Benchmark de bóveda de conocimiento real

OHS también se evalúa en las notas públicas de Andy Matuschak, convertidas en una bóveda de Obsidian con nombres de archivo basados en títulos, URLs de origen en frontmatter, adjuntos locales y 5,000+ enlaces internos entre 1,357 notas.

El conjunto dorado curado incluye 78 consultas juzgadas a mano que abarcan búsqueda de elementos conocidos, paráfrasis, fragmentos de citas, temas ambiguos, búsqueda de citas y evidencia de múltiples notas.

Usando el modelo de incrustación local predeterminado, OHS se desempeña con fuerza en esta densa red de notas.

MétricaValor
nDCG@50.722
nDCG@100.753
MRR0.874
Hit@10.795
Hit@50.974
Recall@100.972
AllRel@100.949

El benchmark ejercita la recuperación sobre una bóveda de conocimiento real altamente conectada, incluyendo consultas que no simplemente repiten títulos de notas.

JSON de resultados · Reproducir e interpretar →

Benchmark de memoria grande

Para probar la recuperación en un conjunto de datos público más grande, LongMemEval-S se convirtió en una bóveda estilo Obsidian de 22,419 notas con 470 consultas de recuperación. Usando incrustaciones baai/bge-m3, OHS clasificó las notas con la respuesta con fuerza:

MétricaValor
nDCG@50.895
MRR0.920
Hit@10.889
Hit@50.968
Recall@100.950
AllRel@100.904

Para este benchmark, cada consulta usa el haystack proporcionado por LongMemEval como su alcance de búsqueda. Eso hace que el resultado sea reproducible y fácil de inspeccionar consulta por consulta, mientras sigue ejercitando la recuperación sobre una bóveda de memoria generada grande.

JSON de resultados · Reproducir e interpretar →

Características

  • Búsqueda híbrida
    • BM25 + título difuso + incrustaciones semánticas, fusionadas con RRF
  • Búsqueda de alias
    • las notas con aliases: en frontmatter se indexan y se pueden buscar por cualquier alias; las coincidencias de alias se potencian en BM25 (peso 5×) y en la puntuación de título difuso
  • Cuatro modos de búsqueda
    • hybrid, semantic, fulltext, title (para consultas de texto)
  • Búsqueda de notas similares
    • pasa --path para encontrar notas semánticamente relacionadas usando incrustaciones de fragmentos almacenadas, con un respaldo de título + contenido
  • Recorrido de grafo
    • --path --related muestra notas enlazadas a profundidad configurable; filtra por --direction outgoing|backlinks|both
  • Enlaces y backlinks
    • cada resultado incluye enlaces salientes y backlinks
  • Filtrado por alcance
    • restringe a subcarpeta(s); admite múltiples valores y exclusiones (-notes/dev/)
  • Filtrado por etiquetas
    • filtra por etiqueta(s); admite múltiples valores y exclusiones (-category/cs)
  • Control de fragmentos
    • --snippet-length establece la ventana de contexto; los fragmentos vacíos siempre recurren al contenido de la nota
  • Salida extendida
    • --extended agrega una columna TAGS/ALIASES a la tabla de la CLI que muestra etiquetas de frontmatter (#tag) y alias
  • Indexación incremental
    • solo reindexa archivos modificados; observa ediciones en tiempo real
  • Expansión de consultas múltiples
    • pasa múltiples consultas a la vez (ohs "q1" "q2" o queries[] en MCP); los resultados se fusionan vía RRF, así que una nota que se clasifica bien en cualquier consulta sube a la cima; útil cuando la nota puede usar vocabulario diferente al de la consulta
  • Reordenamiento con codificador cruzado
    • --rerank re-puntúa los resultados con bge-reranker-v2-m3 (ONNX int8, ~570 MB de descarga única); mejora la precisión para consultas conceptuales y multilingües; se aplica después de la fusión de consultas múltiples
  • Incrustaciones locales
    • funciona sin conexión vía @huggingface/transformers (sin necesidad de clave API); modelo predeterminado: Xenova/multilingual-e5-small, 100+ idiomas
  • Incrustaciones remotas
    • API compatible con OpenAI (OpenRouter, Ollama, etc.)
  • Lectura de notas
    • read obtiene una o más notas por ruta relativa a la bóveda; devuelve el contenido completo con título, alias, etiquetas, enlaces y backlinks; si no encuentra la ruta, devuelve las 3 mejores sugerencias difusas
  • Patrones de ignorar
    • excluye carpetas, extensiones o archivos específicos
  • Plugin de Obsidian

Instalación

npm install -g obsidian-hybrid-search

Uso de la CLI

Inicio rápido

La configuración recomendada es establecer OBSIDIAN_VAULT_PATH una vez en ~/.zshrc o ~/.bashrc. Esto te permite ejecutar la CLI desde cualquier directorio.

export OBSIDIAN_VAULT_PATH="/path/to/your/vault"

Abre una nueva terminal e indexa la bóveda una vez.

ohs reindex

Ahora puedes buscar desde cualquier directorio.

ohs "zettelkasten"

Ejecutar desde una bóveda

Alternativamente, ejecuta la CLI sin una variable de entorno desde cualquier directorio dentro de tu bóveda. Encuentra la raíz de la bóveda subiendo hasta la carpeta .obsidian/ más cercana.

cd /path/to/your/vault
ohs reindex
ohs "zettelkasten"

Desde fuera de la bóveda, establece OBSIDIAN_VAULT_PATH o pasa --db /path/to/vault/.obsidian-hybrid-search.db explícitamente.

Incrustaciones remotas opcionales

Por defecto, la CLI usa el modelo local Xenova/multilingual-e5-small. Funciona sin conexión sin clave API, descarga alrededor de 117 MB en el primer uso y admite más de 100 idiomas.

Para usar una API remota, agrega su configuración a tu perfil de shell.

export OPENAI_API_KEY="sk-..."

# Override the default API base for another provider
# export OPENAI_BASE_URL="https://openrouter.ai/api/v1"  # OpenRouter
# export OPENAI_BASE_URL="http://localhost:11434/v1"     # Ollama (no key needed)
# export OPENAI_BASE_URL="http://localhost:1234/v1"      # LM Studio (no key needed)

# Override the default text-embedding-3-small model
# export OPENAI_EMBEDDING_MODEL="text-embedding-3-small"

Modos de búsqueda

La CLI admite cuatro modos de búsqueda llamados hybrid, fulltext, semantic y title, además del recorrido de grafo para notas enlazadas. Los comandos a continuación muestran cómo usarlos, aplicar filtros, reordenar resultados y controlar la salida.

# Hybrid search (default)
ohs "zettelkasten atomic notes"

# Fulltext BM25 search
ohs "permanent notes" --mode fulltext

# Fuzzy title search (fast, typo-tolerant)
ohs "zettleksten" --mode title

# Semantic / vector search
ohs "how to build a knowledge graph" --mode semantic

# Limit results and set a score threshold
ohs "productivity systems" --limit 5 --threshold 0.3

# Restrict to a subfolder
ohs "daily review" --scope notes/periodic/
ohs "daily review" --folder notes/periodic/    # alias for --scope

# Restrict to multiple subfolders (OR)
ohs "productivity" --scope notes/pkm/ --scope notes/2024/

# Exclude a subfolder
ohs "programming" --scope notes/ --scope -notes/archive/

# Filter by tag
ohs "productivity" --tag pkm
ohs "machine learning" --tag note/basic/primary

# Filter by multiple tags (AND include, exclude with -)
ohs "learning" --tag pkm --tag work

# Filter by frontmatter / properties (exact match, case-insensitive)
ohs "notes" --frontmatter status:todo
ohs "notes" --prop priority:high          # --prop is alias for --frontmatter

# Filter by multiple frontmatter fields (AND)
ohs "notes" --frontmatter status:todo --frontmatter priority:high

# Exclude by frontmatter value
ohs "notes" --frontmatter -status:done

# Filter-only mode: no query, just filters (returns all matching notes sorted by title)
ohs --frontmatter status:todo
ohs --folder notes/2024/
ohs --tag pkm
ohs --frontmatter status:done --tag archived

# Unlimited results in filter-only mode (default limit is 10)
ohs --folder notes/ --limit 0

# Find semantically similar notes
ohs --path notes/pkm/zettelkasten.md

# Graph traversal: show notes linked to/from this note
# Results show depth: -1/-2 = backlinks, 0 = source, +1/+2 = outgoing links
ohs --path notes/pkm/zettelkasten.md --related
ohs --path notes/pkm/zettelkasten.md --related --depth 2

# Only outgoing links (what this note references)
ohs --path notes/pkm/zettelkasten.md --related --direction outgoing

# Only backlinks (who references this note)
ohs --path notes/pkm/zettelkasten.md --related --direction backlinks

# Traverse standard Markdown note links instead of Obsidian wikilinks
ohs --path notes/pkm/zettelkasten.md --related --link-type markdown

# Traverse both wikilinks and standard Markdown note links
ohs --path notes/pkm/zettelkasten.md --related --link-type all

# Longer context around each link
ohs --path notes/pkm/zettelkasten.md --related --snippet-length 500

# Rerank results with a cross-encoder model (improves precision, ~1-3s extra latency)
# Downloads bge-reranker-v2-m3 ONNX (~570 MB) on first use, cached in ~/.cache/huggingface/
ohs "zettelkasten atomic notes" --rerank

# Show tags and aliases alongside results
ohs "zettelkasten" --extended

# JSON output (for scripting)
ohs "spaced repetition" --json

# Output only paths (one per line) — useful for piping into read
ohs --frontmatter id:OHS-4 --only-paths
ohs read ${(f)"$(ohs search --frontmatter status:todo --only-paths)"}  # zsh: read all matching notes

# Output absolute filesystem paths
ohs "zettelkasten" --only-absolute-paths

# Open results in Obsidian (each in a new tab)
ohs "zettelkasten" --open

# Reindex the vault
ohs reindex

# Force full reindex
ohs reindex --force

# Reindex a single file
ohs reindex notes/pkm/zettelkasten.md

# Retry only the notes whose chunks failed to embed
ohs reindex --errors

# Show indexing status
ohs status

# Show recent indexing activity
ohs status --recent

# Show chunks that failed to embed
ohs status --errors

# Read a note by path (outputs body content without frontmatter)
ohs read notes/pkm/zettelkasten.md

# Read raw file from vault (with frontmatter, like cat)
ohs read notes/pkm/zettelkasten.md --raw

# Read multiple notes (separator between each)
ohs read notes/pkm/zettelkasten.md notes/pkm/evergreen-notes.md

# Cap content length
ohs read notes/pkm/zettelkasten.md --snippet-length 2000

# Structured output with all metadata
ohs read notes/pkm/zettelkasten.md --json

Alias de shell

Agrega a tu ~/.zshrc o ~/.bashrc para acceso rápido:

alias ohss='ohs --mode semantic'
alias ohst='ohs --mode title'
alias ohsf='ohs --mode fulltext'
alias ohsr='ohs read'
alias ohsi='ohs reindex'
alias ohsst='ohs status'

Luego recarga (source ~/.zshrc) y usa:

ohs "zettelkasten"                        # hybrid search
ohss "how to build a knowledge graph"     # semantic
ohst "zettelkasten"                       # fuzzy title (typo-tolerant)
ohsf "permanent notes"                    # fulltext BM25
ohsr "notes/pkm/zettelkasten.md"          # read note by path
ohsi                                      # reindex vault
ohsst                                     # show status
ohsst --recent                            # show recent indexing activity
ohsst --errors                            # show chunks that failed to embed

Ejemplo de salida

La búsqueda híbrida devuelve una tabla con puntuaciones y fragmentos. Las puntuaciones están codificadas por colores según la relevancia:

PuntuaciónColorSignificado
0.8 – 1.0verdeAltamente relevante
0.5 – 0.8amarilloModeradamente relevante
0.2 – 0.5normalAlgo relevante
0.0 – 0.2atenuadoBaja relevancia
┌───────┬───────────────────────────────┬────────────────────────────────────────────┐
│ SCORE │ PATH                          │ SNIPPET                                    │
├───────┼───────────────────────────────┼────────────────────────────────────────────┤
│  0.98 │ notes/pkm/zettelkasten.md     │ A note-taking method developed by Niklas   │
│       │                               │ Luhmann. Each note contains one atomic...  │
├───────┼───────────────────────────────┼────────────────────────────────────────────┤
│  0.72 │ notes/pkm/evergreen-notes.md  │ Evergreen notes are written to evolve over │
│       │                               │ time. Unlike fleeting notes, they are...   │
└───────┴───────────────────────────────┴────────────────────────────────────────────┘

Con --extended, se agrega una columna TAGS/ALIASES. Las etiquetas tienen el prefijo #, los alias se muestran tal cual:

┌───────┬───────────────────────────────┬──────────────────┬──────────────────────────────┐
│ SCORE │ PATH                          │ TAGS/ALIASES     │ SNIPPET                      │
├───────┼───────────────────────────────┼──────────────────┼──────────────────────────────┤
│  0.98 │ notes/pkm/zettelkasten.md     │ #pkm             │ A note-taking method...      │
│       │                               │ ЗК               │                              │
│       │                               │ slip-box         │                              │
├───────┼───────────────────────────────┼──────────────────┼──────────────────────────────┤
│  0.72 │ notes/pkm/evergreen-notes.md  │ #pkm             │ Evergreen notes are written  │
│       │                               │ #writing         │ to evolve over time...       │
└───────┴───────────────────────────────┴──────────────────┴──────────────────────────────┘

El modo de título omite la columna de fragmentos automáticamente.

Servidor MCP

La mayoría de los asistentes de IA operan sin acceso a tu conocimiento personal y solo pueden trabajar con lo que pegas en la conversación. Agregar este servidor le da a cualquier asistente compatible con MCP un índice persistente y buscable de toda tu bóveda. Se convierte en una llamada a herramienta, no en una sesión de copiar y pegar: el asistente consulta tus notas de la misma manera que llama a cualquier otra herramienta, obtiene resultados clasificados con fragmentos y enlaces, y puede navegar tu grafo de conocimiento a pedido.

Agrega a tu configuración de MCP (.mcp.json, claude_desktop_config.json, o equivalente para tu cliente).

Configuración mínima (incrustaciones locales, sin clave API)

Usa el modelo integrado Xenova/multilingual-e5-small. Funciona completamente sin conexión y admite 100+ idiomas. Descarga ~117 MB en la primera ejecución.

{
  "mcpServers": {
    "obsidian-hybrid-search": {
      "command": "npx",
      "args": ["-y", "-p", "obsidian-hybrid-search@latest", "obsidian-hybrid-search-mcp"],
      "env": {
        "OBSIDIAN_VAULT_PATH": "/path/to/your/vault"
      }
    }
  }
}

Configuración completa (OpenRouter)

{
  "mcpServers": {
    "obsidian-hybrid-search": {
      "command": "npx",
      "args": ["-y", "-p", "obsidian-hybrid-search@latest", "obsidian-hybrid-search-mcp"],
      "env": {
        "OBSIDIAN_VAULT_PATH": "/path/to/your/vault",
        "OBSIDIAN_PREFIX": "myvault_",
        "OBSIDIAN_RESPECT_GITIGNORE": "true",
        "OBSIDIAN_IGNORE_PATTERNS": ".obsidian/**,templates/**,*.canvas",
        "OBSIDIAN_INCLUDE_PATTERNS": "private/notes/**",
        "OPENAI_API_KEY": "sk-or-v1-...",
        "OPENAI_BASE_URL": "https://openrouter.ai/api/v1",
        "OPENAI_EMBEDDING_MODEL": "openai/text-embedding-3-small"
      }
    }
  }
}

Nota: En la primera ejecución, npx instalará el paquete automáticamente. Los patrones de ignorar se persisten en la base de datos y se restauran en cada inicio posterior incluso si falta la variable de entorno.

Servidor HTTP compartido

Úsalo cuando múltiples clientes MCP deban compartir un único proceso de búsqueda/indexación de larga duración.

Inicia o reutiliza el servidor en segundo plano:

OBSIDIAN_VAULT_PATH="/path/to/your/vault" ohs serve

serve inicia el servidor MCP sobre HTTP por defecto; serve --http es el equivalente explícito. El comando imprime la URL del servidor, el PID, la ruta del registro y un fragmento de configuración del cliente. La dirección de enlace predeterminada es 127.0.0.1:3939.

Luego agrega esto a una configuración de cliente MCP basada en URL (.mcp.json, claude_desktop_config.json, o equivalente):

{
  "mcpServers": {
    "obsidian-hybrid-search": {
      "url": "http://127.0.0.1:3939/mcp"
    }
  }
}

Gestiona el servidor:

ohs serve status
ohs serve stop
ohs serve --foreground
ohs serve --http --foreground

El modo HTTP usa MCP Streamable HTTP sin estado. No emite ni valida Mcp-Session-Id, así que un cliente MCP puede continuar haciendo llamadas a herramientas después de que el daemon se reinicie incluso si aún envía un encabezado de sesión obsoleto. Este modo está pensado para las herramientas de solicitud/respuesta del servidor y no proporciona flujos SSE persistentes, notificaciones iniciadas por el servidor ni reanudación de SSE.

Si el puerto 3939 ya está en uso, el comando sale con un error en lugar de elegir otro puerto automáticamente. Usa --port para bóvedas separadas.

Al vincular más allá de localhost, permite cada nombre de host o dirección que los clientes MCP usarán.

ohs serve \
  --host 0.0.0.0 \
  --allowed-host 192.168.1.20:3939 \
  --allowed-host notes.example.com:3939

Repite --allowed-host para múltiples valores. También puedes establecer una lista separada por comas con OBSIDIAN_MCP_ALLOWED_HOSTS. La opción --allow-any-host desactiva la protección del encabezado Host para redes confiables.

Herramientas MCP disponibles

HerramientaDescripción
searchBuscar en la bóveda. Usa query para búsqueda de texto (mode: hybrid/semantic/fulltext/title) o path para similitud semántica. Combina path con related: true para recorrido de grafos. Pasa queries[] para expansión de múltiples consultas (búsqueda paralela, fusión RRF). Admite scope, tag, limit, threshold, depth, direction, snippet_length, rerank
readObtener una o más notas por ruta relativa a la bóveda. Devuelve contenido completo, título, alias, etiquetas, enlaces y enlaces inversos. Si la ruta no existe: devuelve found: false con las 3 mejores sugerencias difusas. Acepta una sola ruta o un array. Usa snippet_length para limitar el tamaño del contenido
reindexReindexar la bóveda o un archivo específico
statusMostrar el total de notas, el recuento indexado y la última hora de indexación

Establece OBSIDIAN_PREFIX para añadir un prefijo a cada nombre de herramienta. Por ejemplo, myvault_ produce myvault_search y myvault_read. El prefijo está vacío por defecto.

Configuración

Variable de entornoPredeterminadoDescripción
OBSIDIAN_VAULT_PATHRequerido para MCP; el CLI lo detecta automáticamenteRuta absoluta a tu bóveda
OBSIDIAN_PREFIX""Prefijo opcional de herramientas MCP, p. ej. myvault_myvault_search, myvault_read
OBSIDIAN_IGNORE_PATTERNS.obsidian/**,templates/**,*.canvasPatrones de exclusión separados por comas
OBSIDIAN_RESPECT_GITIGNOREtrueLee archivos .gitignore raíz y anidados; establece false para desactivar
OBSIDIAN_INCLUDE_PATTERNS""Patrones separados por comas para re-incluir notas ignoradas solo por .gitignore
OPENAI_API_KEYNingunoClave de API; omítela para usar embeddings de modelos locales o servidores sin clave (Ollama, LM Studio)
OPENAI_BASE_URLhttps://api.openai.com/v1URL base de la API
OPENAI_EMBEDDING_MODELtext-embedding-3-smallNombre del modelo de embeddings

Patrones de exclusión

  • Usa folder/** para ignorar un directorio y todo su contenido.
  • Usa *.canvas para ignorar archivos por extensión.
  • Usa exact/path.md para ignorar un archivo específico.

Los archivos .gitignore raíz y anidados se respetan por defecto. Establece OBSIDIAN_RESPECT_GITIGNORE=false para desactivar este comportamiento. Usa OBSIDIAN_INCLUDE_PATTERNS para re-incluir notas de Markdown que estén ignoradas solo por .gitignore. Los patrones de inclusión no anulan OBSIDIAN_IGNORE_PATTERNS ni las exclusiones internas.

La base de datos almacena la configuración de exclusión y la restaura cuando el servidor se reinicia, incluso si la variable de entorno no está presente.

Cómo funciona

  1. Indexación: divide las notas por encabezados con un respaldo de ventana deslizante, crea embeddings y almacena los resultados en SQLite con FTS5 y sqlite-vec.
  2. Búsqueda: ejecuta BM25, búsqueda difusa de títulos y alias por trigramas, y búsqueda vectorial KNN en paralelo. BM25 usa pesos de 10× para títulos, 5× para alias y 1× para contenido. RRF luego otorga a los resultados semánticos y de BM25 un peso de 1.5× cada uno, coincidencias exactas de alias 2×, y coincidencias difusas parciales 0.25×. Las puntuaciones finales van de 0 a 1, donde puntuaciones más altas significan mayor relevancia.
  3. Enlaces: se resuelven a partir de wikilinks como [[note]], se asignan a rutas de notas y se almacenan. Cada resultado de búsqueda incluye los arrays links y backlinks.
  4. Observador: usa chokidar para detectar cambios en archivos y actualizar el índice en segundo plano.

Contribuciones

Las issues y las pull requests son bienvenidas. Consulta CONTRIBUTING.md para instrucciones de configuración y comprobaciones del proyecto.

Licencia

MIT