Skip to main content
Glama

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)

src/kb/indexer.py

reindex()

detección de cambios por sha256, borrado de huérfanos, rebuild, exclusión de node_modules/.git/etc.

Limpieza de sintaxis Obsidian

src/kb/obsidian.py

preparar_texto()

saca frontmatter YAML, aplana [[wikilinks]]/![[embeds]], antepone el título del archivo

Corte de documentos en fragmentos

src/kb/chunking.py

chunk_text()

tamaño objetivo + solapamiento, por qué importa

RAG · retrieval

src/kb/rag.py

retrieve()

embedding de la query + coseno (producto punto) top-k, todo con numpy

RAG · generation

src/kb/rag.py

answer() / _armar_prompt()

cómo se arma el prompt con el contexto y se pide citar fuentes

Vectores → texto comparable

src/kb/embeddings.py

Embedder (Protocol), get_embedder()

backend local (fastembed, offline) vs gemini (API) detrás de una interfaz

Persistencia

src/kb/store.py

Store

SQLite: tablas files / chunks, embeddings como BLOB float32

MCP (adaptador a herramientas)

src/kb/mcp_server.py

@server.tool()

cada tool es 4 líneas que llaman a rag/indexer

Automatización programada (entregable)

src/kb/digest.py

generar_digest()

reindexar + responder preguntas fijas → Markdown datado

Timer del SO (en vez de cron)

systemd/kb-digest.{service,timer}

OnCalendar, unidad de usuario

CLI

src/kb/cli.py

kb index|search|ask|serve|digest

mismo set de funciones que el MCP, para usar a mano

Config en dos capas

src/kb/config.py

load_config()

secretos/rutas por env (pydantic-settings) + fuentes/preguntas por kb.toml

Reintentos con backoff

src/kb/reintentos.py

con_reintentos()

patrón tenacity para toda llamada a API

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

El 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 gemini

kb.toml se versiona (no tiene secretos). .env no.

Variable

Default

Para qué

EMBEDDINGS_BACKEND

local

local (offline, sin costo) o gemini

KB_DB_PATH

~/.local/share/kb/index.db

dónde vive el índice

KB_CONFIG_PATH

kb.toml

archivo de fuentes/preguntas

GEMINI_API_KEY

solo ask / digest / backend gemini

GEMINI_MODEL

gemini-2.5-flash

modelo de generación

Notas de Obsidian como fuente

Un vault de Obsidian es, para kb, una carpeta más de .mdkb.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 cliente

Conectar a Claude Code (MCP)

claude mcp add kb -- uv run --project /home/loren/projects/kb kb serve

o 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.timer

Local, 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 pytest

29 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 proyecto automatiza-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. Correr kb index dos 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_server solo la envuelve. Desacoplado del transporte.

  • search no necesita API key ni red; ask sí. La parte cara (LLM) está aislada en una sola función.

Lecciones

  • El mcp SDK 2.x renombró FastMCPMCPServer (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.py lo fija).

  • fastembed no soporta todos los nombres de modelo de HuggingFace; hay que elegir de TextEmbedding.list_supported_models(). El multilingüe chico útil es sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2 (384 dims).

  • tomllib (stdlib) es solo lectura y es estricto: [[sources]] no admite un sources = [] antes.

  • Una fuente apuntando a la raíz de un repo indexa node_modules. Pasó en la primera corrida real: ~/projects/roadmap con **/*.md trajo 463 READMEs y CHANGELOGs de dependencias (520 archivos vistos, la mayoría ruido). Se arregló excluyendo siempre node_modules, .git, .venv, dist, etc. — no confiar en que el usuario se acuerde de excluirlos a mano en cada fuente.

Próximos pasos

  • kb ask con 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: search con embeddings locales, ask corto con flash, ask complejo 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 tools
ask_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.

ParametersJSON Schema
NameRequiredDescriptionDefault
questionYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters2/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.2/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
kNo
queryYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters2/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

  1. 3 tool updatesv0.1.0
    • First observedask_knowledge_base
    • First observedreindex_knowledge_base
    • First observedsearch_knowledge_base

TDQS

A3.9/5.0

Scored across 3 tools

Disambiguation4/5

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.

Naming Consistency5/5

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.

Tool Count4/5

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.

Completeness3/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers