kb
Allows indexing an Obsidian vault as a personal knowledge base: cleans Obsidian-specific syntax (YAML frontmatter, wikilinks, embeds), performs incremental indexing, semantic search, and RAG-based questions with citations on local notes.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@kbsearch my Obsidian notes for MCP and cite sources"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
kb — base de conocimiento personal (automatización + RAG + MCP)
Proyecto de aprendizaje (Python). Un flujo realista y chico que combina las tres cosas en un solo código, para ver cómo y dónde encaja cada una:
Automatización → indexado incremental de tus documentos, disparable por timer.
RAG → recuperación semántica + respuesta con LLM citando fuentes.
MCP → esas mismas funciones expuestas como herramientas para Claude Code / Desktop.
Caso de uso: apuntás kb a tus carpetas de notas (roadmap, skills, memory, READMEs
de proyectos, vault de Obsidian) y después preguntás en lenguaje natural desde
la terminal o desde Claude Code (vía MCP), con respuestas ancladas en tus archivos.
Dónde vive cada concepto
Concepto | Archivo | Función clave | Qué mirar |
Automatización (indexado incremental, idempotente) |
|
| detección de cambios por |
Limpieza de sintaxis Obsidian |
|
| saca frontmatter YAML, aplana |
Corte de documentos en fragmentos |
|
| tamaño objetivo + solapamiento, por qué importa |
RAG · retrieval |
|
| embedding de la query + coseno (producto punto) top-k, todo con numpy |
RAG · generation |
|
| cómo se arma el prompt con el contexto y se pide citar fuentes |
Vectores → texto comparable |
|
| backend |
Persistencia |
|
| SQLite: tablas |
MCP (adaptador a herramientas) |
|
| cada tool es 4 líneas que llaman a |
Automatización programada (entregable) |
|
| reindexar + responder preguntas fijas → Markdown datado |
Timer del SO (en vez de cron) |
| — |
|
CLI |
|
| mismo set de funciones que el MCP, para usar a mano |
Config en dos capas |
|
| secretos/rutas por env ( |
Reintentos con backoff |
|
| patrón |
Related MCP server: ai-lab
Cómo se conecta (flujo de datos)
tus .md/.txt ──> indexer.reindex ──> chunking ──> embeddings ──> store (SQLite)
(automatización) │
▼
consulta ──> rag.retrieve (embed query + coseno top-k) ──> chunks relevantes
│
rag.answer: prompt = contexto + pregunta
▼
Gemini ──> respuesta + citas
Claude Code ──(protocolo MCP, stdio)──> mcp_server.tool ──> llama a rag/indexerEl punto clave: RAG e indexado no saben que existe MCP. mcp_server.py es solo
un adaptador. Podrías exponer lo mismo por HTTP, por un bot, o dejarlo solo como CLI.
Instalación
cd /home/loren/projects/kb
uv sync --extra local # --extra local = embeddings offline (fastembed)Sin --extra local funciona igual pero tenés que usar EMBEDDINGS_BACKEND=gemini
(necesita GEMINI_API_KEY).
Configuración
cp kb.example.toml kb.toml # qué carpetas indexar + preguntas del digest
cp .env.example .env # opcional: solo si vas a usar `ask` o el backend geminikb.toml se versiona (no tiene secretos). .env no.
Variable | Default | Para qué |
|
|
|
|
| dónde vive el índice |
|
| archivo de fuentes/preguntas |
| — | solo |
|
| modelo de generación |
Notas de Obsidian como fuente
Un vault de Obsidian es, para kb, una carpeta más de .md — kb.example.toml
ya trae un [[sources]] apuntando a uno. No hace falta marcar nada como
"modo Obsidian": src/kb/obsidian.py limpia la sintaxis propia antes de
trocear y es un no-op sobre markdown común:
saca el frontmatter YAML (
--- ... ---al inicio);aplana
[[Nota]],[[Nota|alias]],[[Nota#sección]]a su texto visible;reemplaza
![[adjunto]]por una referencia corta (no sigue el link);si el cuerpo no empieza con un
#, antepone el nombre del archivo como título — muchas notas de plantilla tienen el dato específico en el nombre y el cuerpo es genérico.
.obsidian/ y .trash/ se excluyen siempre (junto con node_modules, .git,
etc.). Lo específico de tu vault —como una carpeta de plantillas— se excluye
por nombre con excluir en el [[sources]] correspondiente:
[[sources]]
path = "~/Documents/obsidian/tu-vault"
globs = ["**/*.md"]
excluir = ["Templates"]Uso
uv run kb index # indexa (incremental: solo lo que cambió)
uv run kb index --rebuild # borra y reconstruye todo
uv run kb search "cómo desplegué X" # búsqueda semántica, sin LLM (gratis, offline)
uv run kb ask "¿en qué etapa estoy?" # RAG completo con Gemini + citas
uv run kb digest # reindexa + responde las preguntas de kb.toml
uv run kb serve # servidor MCP (stdio) — lo arranca el clienteConectar a Claude Code (MCP)
claude mcp add kb -- uv run --project /home/loren/projects/kb kb serveo copiá .mcp.json.example a .mcp.json en la raíz del repo donde quieras usarlo.
Después, en Claude Code, aparecen las tools search_knowledge_base,
ask_knowledge_base y reindex_knowledge_base.
Automatizar el digest (systemd user timer, no cron)
cp systemd/kb-digest.service systemd/kb-digest.timer ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now kb-digest.timer # corre todos los días 20:00
systemctl --user list-timers kb-digest.timerLocal, sin depender de GitHub Actions ni de una VM encendida.
Verificación
uv run ruff check . && uv run ruff format --check . && uv run mypy src && uv run pytest29 tests, todos offline (usan un FakeEmbedder, no bajan modelos ni llaman APIs).
Decisiones de arquitectura
Interfaz
Embedder(Protocol) con dos backends. El código no sabe si el embedding es local o de API; cambiar es una env var. Mismo patrón que la capa determinista vs. LLM del proyectoautomatiza-tu-dia-a-dia.SQLite + coseno en numpy, sin vector DB. Para una base personal (miles de chunks) el brute-force es instantáneo y se ve toda la matemática de la recuperación. Si algún día son millones, ahí sí entra
sqlite-vec/qdrant.Embeddings normalizados al guardar. Así la búsqueda es un simple producto punto (
matriz @ query), no hay que dividir por normas en cada consulta.Indexado incremental por
sha256. Correrkb indexdos veces seguidas no reindexa nada. Requisito de cualquier automatización que corra por timer.MCP como adaptador delgado. La lógica está en
rag/indexer;mcp_serversolo la envuelve. Desacoplado del transporte.searchno necesita API key ni red;asksí. La parte cara (LLM) está aislada en una sola función.
Lecciones
El
mcpSDK 2.x renombróFastMCP→MCPServer(mcp.server.mcpserver); el API (@server.tool(),server.run("stdio")) es el mismo.Un servidor MCP stdio no puede escribir en stdout (es el canal del protocolo). Todo el logging va a stderr (
kb/reintentos.pylo fija).fastembed no soporta todos los nombres de modelo de HuggingFace; hay que elegir de
TextEmbedding.list_supported_models(). El multilingüe chico útil essentence-transformers/paraphrase-multilingual-MiniLM-L12-v2(384 dims).tomllib(stdlib) es solo lectura y es estricto:[[sources]]no admite unsources = []antes.Una fuente apuntando a la raíz de un repo indexa
node_modules. Pasó en la primera corrida real:~/projects/roadmapcon**/*.mdtrajo 463 READMEs y CHANGELOGs de dependencias (520 archivos vistos, la mayoría ruido). Se arregló excluyendo siemprenode_modules,.git,.venv,dist, etc. — no confiar en que el usuario se acuerde de excluirlos a mano en cada fuente.
Próximos pasos
kb askcon historial (multi-turno) manteniendo el contexto recuperado.Un segundo servidor MCP que además escriba (crear/editar notas) → ya es un agente con tools de lectura y escritura.
Router de modelos:
searchcon embeddings locales,askcorto con flash,askcomplejo con un modelo más grande — decidido por una función.Reranking de los top-k antes de armar el prompt (cross-encoder chico).
Available Tools
3 toolsask_knowledge_baseA
Responde una pregunta con RAG sobre la base local: recupera contexto y genera una respuesta con Gemini, citando los archivos fuente. Necesita GEMINI_API_KEY configurada.
| Name | Required | Description | Default |
|---|---|---|---|
| question | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry the behavioral burden. It discloses that the tool uses RAG, generates with Gemini, cites sources, and requires GEMINI_API_KEY. It does not explicitly state whether the operation is read-only or describe error handling for missing keys or empty results, but the core behavior is transparent enough for an agent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, efficient sentence that front-loads the main action and then adds the prerequisite. Every clause adds value: the retrieval, generation, citation, and API key requirement are all included without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity (RAG pipeline with external API) and the existence of an output schema, the description covers the essential call-time information: the question input and the required environment variable. It doesn't describe potential failure modes or the exact answer format, but the output schema likely covers return values, so the description is fairly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It only clarifies that the tool 'answers a question', directly linking the 'question' parameter to its purpose, but adds no further details such as format, length limits, or examples. Minimal compensation is provided.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: it answers a question using RAG, retrieves context, generates a response with Gemini, and cites source files. This is a specific verb-resource pair that distinctly separates it from siblings like search_knowledge_base (which likely returns raw matches) and reindex_knowledge_base (which rebuilds the index).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage: it is for generative question answering with citations, as opposed to raw search or reindexing. However, it does not explicitly mention alternatives or give when-to-use/when-not-to-use guidance, leaving the differentiation to inference from the siblings' names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reindex_knowledge_baseA
Re-indexa (incremental) las carpetas configuradas en kb.toml. Solo procesa lo que cambio desde la ultima corrida.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral disclosure burden. It discloses incremental behavior and the configuration source, but does not mention side effects, permissions, idempotency, or failure behavior for a mutating maintenance operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short, information-dense sentences with no filler. The key facts—what is reindexed, incremental mode, and change-based processing—are presented clearly and front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter reindexing tool, the description is largely complete: it states the target folders, the config source, and the incremental behavior. A note about when to trigger it or what side effects occur would be nice, but nothing essential is missing for invoking it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and 100% schema coverage, so there are no parameter details to document. The description adds useful context by identifying kb.toml as the source of what gets reindexed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific action ('Re-indexa'), a concrete resource ('las carpetas configuradas en kb.toml'), and a mode ('incremental'), which makes the tool's role immediately clear. It is easily distinguished from sibling query tools like search_knowledge_base and ask_knowledge_base.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description conveys that this tool is meant for refreshing the index after changes, since it only processes what changed since the last run. It does not explicitly name search/ask as alternatives, but the maintenance-vs-query distinction is strongly implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_knowledge_baseA
Busqueda semantica en la base local. Devuelve los fragmentos mas relevantes con su ruta de archivo y un score de similitud (0-1). No usa LLM.
| Name | Required | Description | Default |
|---|---|---|---|
| k | No | ||
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It discloses the return format (fragments with file path and similarity score 0-1) and the key behavioral trait of not using an LLM. However, it does not mention whether the operation is read-only or if there are side effects, though 'search' strongly implies read-only. It provides useful behavioral context beyond what the schema offers.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three short sentences with zero waste. The purpose is front-loaded, and the key differentiator ('No usa LLM') is placed at the end but still succinct. Every sentence earns its place; there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (2 params, one required) and the presence of an output schema, the description covers the core return format and the non-LLM aspect. However, it leaves the 'k' parameter unexplained, and with no annotations, it also fails to clarify that the operation is read-only. These gaps make the description only moderately complete for an agent to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate for undocumented parameters. It implies that 'query' is the search term but does not explicitly describe it, and it completely omits 'k' (which controls the number of results). The description adds some meaning to 'query' but fails to explain 'k', leaving a parameter undocumented in both schema and description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb (semantic search) and resource (local knowledge base), and differentiates from siblings by explicitly stating 'No usa LLM' (does not use LLM), which distinguishes it from ask_knowledge_base. The purpose is unambiguous and distinguishes from reindex as well.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use this tool by noting it does not use an LLM, suggesting it is for direct retrieval rather than synthesized answers. It doesn't name the alternative explicitly, but the key differentiator is present, allowing an agent to infer the correct tool based on whether LLM-based processing is needed. This is clear context but not an explicit when-not statement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.1.0- First observed
ask_knowledge_base - First observed
reindex_knowledge_base - First observed
search_knowledge_base
TDQS
Scored across 3 tools
The three tools are clearly distinct: search returns raw fragments, ask generates an LLM answer with citations, and reindex refreshes the index. The only minor overlap is that search and ask both retrieve from the knowledge base, but their outputs and purposes are different enough.
All tool names follow a consistent verb_noun pattern: search_knowledge_base, ask_knowledge_base, reindex_knowledge_base. The verbs are distinct and the object is consistent, making the pattern predictable.
Three tools is a reasonable, focused set for a knowledge base server. It covers the core operations (search, ask, reindex) without unnecessary bloat, though it is on the smaller side.
The core operations are covered: retrieval, RAG-based Q&A, and index maintenance. However, there is no tool to add, update, or delete documents directly, and no way to inspect the index status or configuration, which could be a gap depending on the intended workflow.
Maintenance
Related MCP Connectors
- TaprootOAuthcom.taproothq
Persistent memory layer for AI tools. Save and recall notes across Claude and other MCP clients.
MCP-native notes and memory for ChatGPT, Claude, and other AI tools.
Private persistent memory for Claude, ChatGPT & Gemini via MCP - semantic search, zero-code setup.
Search, read, and write your Apple Notes from ChatGPT/Claude via a local Mac agent + MCP relay.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables Claude Code to index and semantically search through PDFs, code, and documents with exact citations and zero hallucinations.MIT
- AlicenseNot gradedqualityBmaintenanceEnables Claude Code to search and retrieve from a local knowledge base of markdown notes using hybrid semantic+keyword search, keeping data entirely offline.4 npmMIT
- FlicenseNot gradedqualityCmaintenanceEnables semantic search over personal study notes by exposing a vector search tool that Claude Desktop can call to retrieve relevant note content and synthesize grounded answers.-
- FlicenseNot gradedqualityAmaintenanceEnables semantic search over personal markdown notes by indexing them into a vector database and exposing search, reindex, and status tools via MCP.-