OKF Knowledge Agent MCP Server
understory 🌱
Memoria que crece.
La capa bajo tus agentes: una memoria de markdown plano que se auto-conecta. Cada hecho que tus agentes aprenden se archiva como un concepto markdown, se enlaza cruzadamente en un grafo de conocimiento vivo, y el propio agente lo mantiene sano: buscable, con capacidad de diff y totalmente tuya. Funciona muy bien con modelos locales.
Los bundles siguen la especificación Open Knowledge Format (OKF) v0.1: archivos markdown plano con frontmatter YAML, legibles por humanos, con diff en git y portables entre herramientas.
Tres vías de entrada, un solo agente:
Servidor MCP — herramientas
memory_query/memory_add/memory_update/memory_status/memory_maintainsobre stdio o HTTP transmisible. Cada llamada impulsa un agente LLM interno con la especificación OKF en su prompt del sistema.Interfaz web — explora el bundle (árbol, visor de conceptos, registro de actualizaciones, insignia de conformidad), ve la memoria como un grafo dirigido por fuerzas estilo Obsidian (arrastrar/desplazar/zoom, coloreado por tipo, tamaño según conexiones, huérfanos con anillo rojo, clic para abrir) y chatea con el mismo agente para probarlo. Las llamadas a herramientas se renderizan en línea para que puedas ver cómo funciona.
Reproducción de rutas de consulta — cada ejecución del agente (consulta/mutación/chat) registra su recorrido (búsquedas → lecturas → escrituras) como una notación compacta, persistida en
<bundle>/.traces/. La vista de grafo lista las ejecuciones recientes; al seleccionar una, se reproduce la ruta como saltos dirigidos numerados sobre el grafo: los conceptos visitados con anillo, los resultados de búsqueda punteados, todo lo demás atenuado.CLI — entradas de prueba
pnpm agent:query "..."/pnpm agent:mutate "...".
Regla de diseño: la conformidad se aplica en el código, no en los prompts. La capa determinista de bundles valida el frontmatter (type obligatorio), regenera los archivos index.md, añade entradas a log.md (de más reciente a más antigua, especificación §7) y limita todas las rutas a la raíz del bundle. El LLM decide qué cambiar; el código garantiza que el resultado sea un bundle conforme.
Inicio rápido (Docker)
No necesitas clonar nada: la imagen es pública. Guarda esto como docker-compose.yml:
services:
understory:
image: ghcr.io/thecodacus/understory:latest
ports:
- "3800:3800"
# Lets the container reach a llama.cpp server running on the host via
# http://host.docker.internal:8080/v1 (see "Local llama.cpp" below).
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
# Your memory lives here as plain markdown — a named volume, or point
# a bind mount (e.g. ./my-memory:/bundle) at any OKF bundle.
- understory-memory:/bundle
environment:
BUNDLE_ROOT: /bundle
LLM_API_BASE_URL: ${LLM_API_BASE_URL}
LLM_API_KEY: ${LLM_API_KEY}
LLM_API_FORMAT: openai
LLM_MODEL: ${LLM_MODEL:-}
# Optional fallback
LLM_FALLBACK_API_BASE_URL: ${LLM_FALLBACK_API_BASE_URL:-}
LLM_FALLBACK_API_KEY: ${LLM_FALLBACK_API_KEY:-}
LLM_FALLBACK_API_FORMAT: ${LLM_FALLBACK_API_FORMAT:-openai}
LLM_FALLBACK_MODEL: ${LLM_FALLBACK_MODEL:-}
restart: unless-stopped
volumes:
understory-memory:docker compose up -dElegir un proveedor
El sistema genérico de proveedores admite cualquier API compatible con OpenAI o Anthropic.
Configura LLM_API_BASE_URL + LLM_API_KEY + LLM_MODEL y deja LLM_PROVIDER sin establecer.
DeepSeek:
LLM_API_BASE_URL=https://api.deepseek.com/v1 LLM_API_KEY=sk-... LLM_MODEL=deepseek-chatOpenAI:
LLM_API_BASE_URL=https://api.openai.com/v1 LLM_API_KEY=sk-... LLM_MODEL=gpt-4oAnthropic (Claude):
LLM_API_BASE_URL=https://api.anthropic.com/v1 LLM_API_KEY=sk-ant-... LLM_API_FORMAT=anthropic LLM_MODEL=claude-sonnet-5Groq:
LLM_API_BASE_URL=https://api.groq.com/openai/v1 LLM_API_KEY=gsk_... LLM_MODEL=llama-3.3-70b-versatilellama.cpp local:
LLM_API_BASE_URL=http://host.docker.internal:8080/v1 LLM_MODEL=Cuando understory se ejecuta en Docker,
localhostes el propio contenedor, no el host — así que un llama-server en el host se alcanza enhost.docker.internal(los archivos compose anteriores ya lo mapean medianteextra_hosts). Si se ejecuta desde el código fuente en la misma máquina que llama-server, usahttp://localhost:8080/v1.
llama.cpp local con respaldo de DeepSeek:
LLM_API_BASE_URL=http://host.docker.internal:8080/v1 LLM_MODEL= \
LLM_FALLBACK_API_BASE_URL=https://api.deepseek.com/v1 LLM_FALLBACK_API_KEY=sk-... LLM_FALLBACK_MODEL=deepseek-chatLas antiguas variables de entorno LLM_PROVIDER + clave por proveedor siguen funcionando (compatibles hacia atrás), pero están obsoletas.
A continuación:
Interfaz web → http://localhost:3800 — explora la memoria, observa el grafo, chatea con el agente
Endpoint MCP →
http://localhost:3800/mcp(HTTP transmisible) — regístralo en cualquier cliente MCP:claude mcp add --transport http ustory http://localhost:3800/mcpTu agente ahora tiene
memory_query/memory_add/memory_update/memory_status/memory_maintain, y recibe un resumen inicial de la memoria al comienzo de cada sesión.
Enséñale algo (memory_add: «Desplegamos los viernes, nunca los lunes»), luego abre el grafo y observa cómo el concepto se integra solo. ¿Despliegas con Portainer? Usa docker-compose.portainer.yml como stack de repositorio.
Related MCP server: Kremis
Pila tecnológica
Monorepo pnpm:
Paquete | Descripción |
| Capa de bundles OKF (sin LLM) + agente (bucle de herramientas de Vercel AI SDK: search/read/list/write/patch/delete) + registro de proveedores |
| Express: MCP streamable-HTTP en |
| Vite + React + TS + Tailwind: navegador de bundles + chat con agente ( |
Los proveedores se configuran mediante LLM_API_BASE_URL, LLM_API_KEY, LLM_API_FORMAT (openai o anthropic) y LLM_MODEL. Cualquier endpoint compatible con OpenAI (DeepSeek, OpenAI, Groq, OpenRouter, llama.cpp, etc.) funciona con LLM_API_FORMAT=openai; los endpoints compatibles con Anthropic usan LLM_API_FORMAT=anthropic. El respaldo opcional usa las variables LLM_FALLBACK_* correspondientes.
llama.cpp
# on the inference box — --jinja enables OpenAI-style tool calling
llama-server -m model.gguf --jinja --host 0.0.0.0 --port 8080
# here — no model id needed, it's discovered for llama-server-like local endpoints
LLM_API_BASE_URL=http://inference-box:8080/v1 LLM_API_FORMAT=openai LLM_MODEL= \
BUNDLE_ROOT=./sample-bundle node packages/server/dist/index.jsTambién funciona detrás de llama-swap: la detección prefiere el modelo actualmente cargado para que una consulta no provoque un cambio de modelo de varios minutos. Fija un modelo concreto con LLM_MODEL=.
Desde el código fuente
pnpm install
pnpm build
cp .env.example .env # add your API key
BUNDLE_ROOT=./sample-bundle \
LLM_API_BASE_URL=https://api.deepseek.com/v1 \
LLM_API_KEY=sk-... \
LLM_API_FORMAT=openai \
LLM_MODEL=deepseek-chat \
node packages/server/dist/index.js
# → http://localhost:3800 (web UI + /api + /mcp)O construye el contenedor tú mismo: docker compose up --build (el docker-compose.yml del repositorio compila desde el código fuente y monta ./sample-bundle).
Modo de desarrollo (servidor en :3800, Vite HMR en :5180 con proxy):
BUNDLE_ROOT=./sample-bundle pnpm --filter @understory/server dev
pnpm --filter @understory/web devRegistro de MCP (Claude Code / Desktop)
claude mcp add ustory \
-e BUNDLE_ROOT=/path/to/your/bundle \
-e LLM_API_BASE_URL=https://api.deepseek.com/v1 \
-e LLM_API_KEY=sk-... \
-e LLM_API_FORMAT=openai \
-e LLM_MODEL=deepseek-chat \
-- node /path/to/understory/packages/server/dist/mcp/stdio.jsO apunta un cliente MCP HTTP a http://host:3800/mcp.
Autenticación
Por defecto el servidor está abierto: correcto en localhost o en una LAN de confianza. Antes de exponerlo en cualquier otro lugar, establece AUTH_TOKEN:
AUTH_TOKEN=$(openssl rand -hex 24)Con esto establecido, /mcp y /api requieren Authorization: Bearer <token> (la interfaz web sigue siendo accesible y solicita el token). Registra clientes MCP autenticados con una cabecera:
claude mcp add --transport http ustory http://host:3800/mcp \
--header "Authorization: Bearer <token>"El transporte stdio no necesita token: es un proceso local lanzado por el cliente.
Memoria semilla
Un LLM cliente que solo ve cuatro nombres de herramientas a secas nunca tiene el instinto de consultar la memoria. Así que al inicio de la sesión el servidor inyecta un resumen compacto de lo que contiene la base de conocimiento (directorios, conceptos con tipos + descripciones, actividad reciente) a través de ambos canales que llegan al modelo:
el campo
instructionsde la inicialización MCP (clientes como Claude lo ponen en el prompt del sistema), yla descripción de la herramienta
memory_query— el respaldo universal que carga todo cliente que llama a herramientas.
La semilla se regenera desde cero para cada sesión. Después de memory_add / memory_update en una sesión de larga duración (stdio), la descripción de la herramienta se actualiza mediante tools/list_changed, de modo que la sesión ve sus propias escrituras. Las ediciones fuera de banda (ediciones manuales, otros clientes) se detectan en la siguiente sesión.
Salud y mantenimiento del grafo
La memoria es un grafo, no un montón de notas, y los grafos se deterioran: los conceptos quedan huérfanos (nada enlaza a ellos) y los enlaces se rompen. Dos mecanismos la mantienen sana:
Enlazado en el momento de escritura — el nuevo conocimiento o bien enriquece el concepto al que pertenece (un atributo de una entidad existente se incorpora mediante un parche, no se archiva por separado) o, cuando se trata de una entidad distinta, se crea y se enlaza de vuelta desde los conceptos relacionados. Las contradicciones se reemplazan in situ, nunca se dejan en pie junto al valor antiguo.
memory_maintain— un lint determinista (huérfanos + enlaces rotos, expuestos enmemory_statusbajograph) impulsa a un agente interno a conectar los huérfanos con conceptos relacionados y arreglar los enlaces colgantes. Ejecútalo periódicamente para contrarrestar la deriva; no hace nada cuando el grafo ya está sano.
Este diseño refleja el patrón del LLM Wiki de Karpathy (index.md + log.md, crear-vs-enriquecer, lint de huérfanos). Se difiere de ese patrón hasta que la escala lo justifique: un esquema explícito de tipos de página y búsqueda híbrida FTS5+embeddings (el escaneo simple en search.ts funciona bien hasta unos pocos miles de conceptos).
Pruebas
pnpm test # core: 18 tests (spec §5/§6/§7/§9, sandbox, search, concurrency)
pnpm --filter @understory/server exec tsx scripts/mcp-smoke.mts # MCP stdio round-trip (needs SMOKE_BUNDLE + an API key)Entorno
Consulta .env.example. BUNDLE_ROOT es obligatorio; GIT_AUTOCOMMIT=true hace commit de cada mutación.
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 Connectors
Knowledge base MCP for AI agents on iknow.dev. Search, read, and maintain via OAuth.
AI Reasoning Cache & Consensus Layer with 11 MCP tools via Streamable HTTP.
Shared, governed long-term memory for AI agents across tools and sessions via MCP and REST.
Private-by-default, local-first memory/context/task orchestrator for MCP apps and agents.
Related MCP Servers
- AlicenseAqualityAmaintenanceMCP server exposing a deterministic, local knowledge graph over stdio. Zero LLM calls in the bridge; answers are classified as Fact, Inference, or Unknown and persisted in redb (ACID, BLAKE3-hashed).1014Apache 2.0
- AlicenseNot gradedqualityBmaintenanceA local OKF-compatible knowledge engine for AI agents. Enables capturing agent conversations, hybrid semantic+keyword search, MCP serving to agents, interactive graph visualization, and OKF bundle export.Apache 2.0
- AlicenseNot gradedqualityBmaintenanceProvides LLM agents with a structured, queryable, local-first knowledge base with typed documents and full-text search via MCP.MIT
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/thecodacus/understory'
If you have feedback or need assistance with the MCP directory API, please join our Discord server