th-memory-mcp
Servidor MCP de memoria a largo plazo para OpenCode y otros entornos: almacena preferencias, lecciones e historial de uso en un único archivo local SQLite (100% local, sin API externa) para que la IA pueda "recordar y adaptarse" al usuario mediante aprendizaje basado en contexto.
Documentación
th-memory-mcp
Estado: v2.3.0 — un motor de memoria temporal, consciente de conflictos y con recuperación híbrida. 16 herramientas MCP, 25 suites de pruebas aprobadas. Migración de esquema no destructiva desde v1 (todos los datos de v1 se conservan). Nuevo en v2.2: estados de ciclo de vida, validez temporal, resolución de conflictos/deduplicación con alcance USER/SESSION/PROJECT/GLOBAL, recuperación híbrida FTS+vectorial (RRF), grafo de memoria, ensamblaje de get_context, consolidación periódica y link_memory / merge_memory / update_memory / import_memory / extract_memories. Nuevo en v2.2.3: recuperación con alcance forzado, aislamiento de alcance en el grafo, ida y vuelta de exportación/importación, ruta de importación endurecida (realpath), validación estricta de importación, eliminación de consultas N+1, punto de referencia en frío/ablación e interruptor MEMORY_RETRIEVAL_MODE. Nuevo en v2.2.7: filtro de secretos sincronizado entre el hook de Claude y capture-core (redacción de 6 patrones en lugar de eliminar líneas), corrección de err() para devolver isError:true según la especificación MCP, corrección de la rotación de copias de seguridad (copia solo cuando hay migraciones pendientes + poda a 5 archivos) y registro de errores de hook para el destilado de SessionEnd. Nuevo en v2.2.8: corrección de contaminación de alcance 0.75→0 (crítico) y falso conflicto 0→1 (fuga GLOBAL), corrección de grafo hop1 0.52→1.0 mediante includeGraph, y reescalado de perfiles de referencia a 5K/20K/100K/500K/1M (pre-commit ahora rápido 5K + normal 20K solamente). Nuevo en v2.2.9: extensión de exportación a entidades/usuarios/relaciones, forget ahora elimina enlaces asociados, migración con cierre ante fallos con helper ISO compartido, eliminación de N+1 en FTS, inclusión de smoke en el script de pruebas y sincronización del visor con perfiles reescalados 5K/20K/100K/500K/1M. Nuevo en v2.3.0: CLI th-memory + subrayado de resaltado.
Requisitos
- Node.js >= 20 — el servidor utiliza APIs exclusivas de Node (la compilación nativa de
better-sqlite3y la resolución deimport.meta.url) y el SDK de MCP requiere un runtime moderno. Las pruebas de CI se ejecutan en Node 20.x y 22.x. - npm — para instalar dependencias y ejecutar los scripts de compilación/pruebas (
npm install,npm run build,npm test). - OpenCode — el host que carga este servidor MCP y el plugin de captura automática. Cualquier compilación que admita MCP sobre stdio + plugins funciona; el plugin se ejecuta en el runtime Bun incluido de OpenCode.
- SO: Windows / macOS / Linux — el servidor es multiplataforma (Node). El plugin de captura automática se ejecuta dondequiera que se ejecute el runtime Bun de OpenCode. Nota para Windows:
MEMORY_DB_PATHes más fácil de configurar consetx; en macOS/Linux usaexporten tu perfil de shell.
No se requieren servicios externos, cuentas ni claves API — todo vive en un único archivo SQLite local.
Inicio rápido
Ruta más rápida: después de clonar, ejecuta npm run quickstart — compila, conecta opencode.json, despliega el plugin y configura MEMORY_DB_PATH por ti en un solo comando. Los pasos a continuación muestran exactamente lo que hace (úsalos si prefieres control manual).
Instalación vía npm (alternativa): instala el servidor globalmente con npm install -g th-memory-mcp (o ejecútalo bajo demanda con npx th-memory-mcp), luego apunta el mcp command en opencode.json a th-memory-mcp en lugar del dist/index.js compilado. El plugin de captura automática aún proviene de este repositorio (copia src/plugin/learning-capture.ts como se describe en el paso 4 a continuación).
Nota: ya no se publica en GitHub Packages — instala desde npmjs con
npm i -g th-memory-mcp.
# 1. Clone and build
git clone https://github.com/worakorn-prince/th-memory-mcp.git
cd th-memory-mcp
npm install
npm run build
# 2. Share one DB between the server and the plugin
# Windows (PowerShell):
setx MEMORY_DB_PATH "$PWD/data/memory.db"
# macOS / Linux (add to your shell profile, e.g. ~/.zshrc):
# export MEMORY_DB_PATH="$PWD/data/memory.db"
- Fusiona esto en tu
~/.config/opencode/opencode.json(reemplaza<REPO>con la ruta absoluta del clon):
{
"instructions": ["<REPO>/AGENTS.memory.example.md"],
"mcp": {
"memory": {
"type": "local",
"command": ["node", "<REPO>/dist/index.js"],
"enabled": true,
"environment": { "MEMORY_DB_PATH": "<REPO>/data/memory.db" }
}
}
}
- (Opcional) Captura automática: copia
src/plugin/learning-capture.ts→~/.config/opencode/plugins/ - Reinicia OpenCode
- Pruébalo: "Recuerda que prefiero pnpm" → nueva sesión → "¿Qué gestor de paquetes prefiero?"
Arquitectura
OpenCode ──┬─ Plugin learning-capture (Bun) ── auto-captures prompts/tool/error into DB
│ └─ injects profile back into context on compaction
└─ MCP th-memory-mcp (Node.js stdio) ── 16 tools read/write the same SQLite DB
▲
Global instructions (memory-protocol.md) teach the AI to use the tools
Consulta ARCHITECTURE_v2.md para la especificación completa de la arquitectura.
¿Por qué th-memory-mcp?
Los LLM no te recuerdan entre sesiones — cada nuevo chat comienza en blanco. th-memory-mcp le da a tu IA una memoria a largo plazo privada y local:
- Aprendizaje basado en contexto, no fine-tuning — captura tus preferencias, correcciones y hábitos, luego los recupera en el contexto la próxima vez. El mismo mecanismo que las funciones de memoria de los principales productos de IA, sin enviar ningún dato fuera de tu máquina.
- 100% local y privado — un único archivo SQLite, sin nube, sin API externa. Los secretos se filtran antes de almacenar cualquier cosa.
- Baja sobrecarga — cada llamada de herramienta está limitada (latencia < 10 ms, tamaño de salida acotado) y la IA solo consulta la memoria cuando es realmente útil, por lo que nunca infla tu contexto.
- Resiliente — cada herramienta se degrada con elegancia; si la base de datos no está disponible, la IA sigue funcionando en lugar de fallar.
- Abierto y extensible — licencia MIT, 16 herramientas documentadas, un destilado basado en reglas y un plugin de captura automática que puedes adaptar.
Funciona con otros harnesses
th-memory-mcp es un servidor MCP estándar, por lo que las 9 herramientas se ejecutan en cualquier lugar donde se admita MCP sobre stdio. La captura automática completa (captura en segundo plano de prompts/herramientas/errores + inyección de perfil) necesita un runtime de hooks — OpenCode lo tiene integrado; Claude Code lo obtiene mediante nuestro puente de hooks; Codex y Cursor usan las herramientas manualmente (aún sin runtime de hooks).
| Función | OpenCode | Claude Code | Qwen Code | Codex | Cursor |
|---|---|---|---|---|---|
| 16 herramientas MCP | ✅ | ✅ | ✅ | ✅ | ✅ |
| Captura automática (segundo plano) | ✅ plugin | ✅ hooks | ⚠️ adaptador | ❌ manual | ❌ Rules |
| Inyección de perfil | ✅ compactación | ✅ UserPromptSubmit | ❌ get_profile | ❌ get_profile | ❌ get_profile |
| Coincidencia difusa léxica | ✅ (v2.0) | ✅ (v2.0) | ✅ (v2.0) | ✅ (v2.0) | ✅ (v2.0) |
- Claude Code: consulta CLAUDE_CODE_HOOKS.md — los hooks de instalación directa replican el plugin de OpenCode (captura + inyección de perfil en
UserPromptSubmit/PreCompact, destilado basado en reglas enSessionEnd). - Qwen Code: consulta QWEN_SETUP.md — MCP funciona completamente; los hooks usan el esquema de Gemini-CLI, por lo que la captura automática necesita un pequeño adaptador.
- Codex: consulta CODEX_SETUP.md
- Cursor: consulta CURSOR_SETUP.md
Todos los harnesses comparten un único archivo SQLite mediante MEMORY_DB_PATH, por lo que la memoria capturada en cualquier lugar es legible en todos.
Destacados
- Memoria estructurada — preferencias con puntuación de confianza más registros dedicados de
lesson(situación → error → corrección) para capturar correcciones, no solo hechos planos. - Ciclo de vida y temporal — cada memoria tiene un estado de ciclo de vida (activa/obsoleta/superada/archivada), puntuación de confianza/importancia/saliencia, decaimiento por tipo e intervalos de validez para que la IA pueda razonar sobre la verdad en un punto temporal y cadenas de superación.
- Consciente de conflictos — detección de duplicados, detección de contradicciones y resolución de actualización/superación preservan ambos lados de la evidencia ambigua en lugar de sobrescribir silenciosamente.
- Recuperación híbrida —
get_contextcombina la búsqueda de palabras clave FTS5 con una coincidencia difusa léxica sin dependencias (similitud de n-gramas con hash, FNV-1a de 512 dimensiones) (fusión RRF + puntuación), luego ensambla un contexto con presupuesto de tokens con expansión opcional del grafo de memoria. - Consolidación — agrupación periódica de memorias similares en memorias derivadas con procedencia completa (enlaces
derived_from). - Tailandés de primera clase / i18n — tokenización consciente del tailandés en el destilado; la IA acepta tailandés e inglés indistintamente.
- Privado por defecto — un único archivo SQLite local, sin nube, sin claves API, con líneas secretas (
api_key=,password:,token) filtradas antes del almacenamiento. - Multi-harness — se ejecuta en OpenCode, Claude Code, Codex y Cursor compartiendo una base de datos; captura automática + inyección de perfil mediante el plugin de OpenCode o los hooks de Claude.
- Ligero y resiliente — Node +
better-sqlite3, sin extensiones nativas adicionales; cada herramienta se degrada con elegancia para que la IA siga funcionando si la base de datos no está disponible.
Scripts
| Comando | Descripción |
|---|---|
npm run build | compilar TypeScript → dist/ |
npm start | ejecutar el servidor MCP (stdio) desde dist/index.js |
npm run distill | destilado basado en reglas: interacciones → secciones de perfil + poda de datos antiguos (env RETENTION_DAYS predeterminado 30) |
npm test | suite completa: captura, destilado, ciclo de vida, temporal, conflictos, recuperación, grafo, contexto, consolidación, punto de referencia, seguridad, tools_v21, smoke, e2e_transport, retrieval_benchmark, recall_regression, scope, perfil, extracción de entidades, conflict_benchmark, security_regression, export_import_roundtrip |
node test/capture.test.mjs | probar capture-core (filtrar secretos, deduplicar, truncar, insertar SQL) |
node test/distill.test.mjs | probar distill-core (tokenización tailandesa, estadísticas, secciones de perfil, poda) |
node test/lifecycle.test.mjs | probar el motor de ciclo de vida (estados, decaimiento, superación) |
node test/temporal.test.mjs | probar el modelo temporal (validez, recuperación histórica) |
node test/conflict.test.mjs | probar la resolución de conflictos y deduplicación |
node test/retrieval.test.mjs | probar la recuperación híbrida FTS+vectorial+RRF |
node test/graph.test.mjs | probar el grafo de memoria (entidades, relaciones, recorrido) |
node test/context.test.mjs | probar el ensamblaje de contexto + presupuesto de tokens |
node test/consolidation.test.mjs | probar la agrupación + memorias derivadas |
node test/benchmark.test.mjs | punto de referencia de latencia sobre 300 memorias |
node test/security.test.mjs | comprobaciones de inyección / seguridad |
node test/smoke.mjs | prueba de humo de extremo a extremo sobre JSON-RPC (16 herramientas) |
Herramientas (16)
| Herramienta | Descripción |
|---|---|
remember | insertar o actualizar preferencia (categoría+clave) — volver a guardar la misma clave aumenta la confianza en 0.1 (máximo 1.0) |
recall | buscar preferencias + lecciones (FTS5) + interacciones coincidentes recientes. Úsalo antes de comenzar una nueva tarea |
get_profile | resumen del perfil de usuario: secciones de perfil + preferencias principales + 5 lecciones más recientes |
save_lesson | registrar una lección aprendida de una corrección (situación / error / corrección) |
search_history | buscar prompts de usuario anteriores por palabra clave (fragmentos de 200 caracteres por fila) |
forget | eliminar una fila de memoria (preferencia/lección/interacción) por id (+tipo evita choque de id entre tablas) |
memory_stats | estadísticas de memoria: conteos por tipo, tamaño de la base de datos, interacción más antigua/más reciente, secciones de perfil |
get_recent_interactions | listar interacciones crudas recientes (filtrar por tipo) — materia prima para Smart Distill |
export_memory | exportar memoria a JSON bajo data/exports/ solamente (nombre de archivo auto-saneado) |
get_context | ensamblar memorias relevantes para la tarea actual mediante recuperación híbrida (+ expansión opcional del grafo) con presupuesto de tokens |
consolidate | agrupar memorias similares mediante similitud de embeddings; opcionalmente crear memorias derivadas/consolidadas enlazadas mediante derived_from |
link_memory | crear una relación tipada entre dos memorias en el grafo (supports/contradicts/supersedes/derived_from/related_to/caused_by/depends_on) |
merge_memory | fusionar un duplicado/casi duplicado en una memoria canónica (la fuente se vuelve superada, procedencia en metadata.merged_from) |
update_memory | actualizar campos mutables en el lugar, o crear una memoria superadora cuando content cambia (establece supersede=false para editar en el lugar) |
import_memory | importar memorias desde JSON (valida tipo, deduplica contra existentes, nunca sobrescribe a ciegas); simulación por defecto, apply=true para insertar |
extract_memories | escanear interacciones capturadas recientes en busca de frases con intención de memoria y proponer candidatos de memoria (determinista, sin LLM); simulación por defecto, apply=true para crear (fuente=capturada) |
CLI (th-memory)
Dos binarios se incluyen en package.json (bin):
| Binario | Entrada | Propósito |
|---|---|---|
th-memory-mcp | dist/index.js | servidor MCP (stdio) — las 16 herramientas anteriores |
th-memory | dist/cli.js | CLI de memoria local (sin dependencias, comparte la misma base de datos mediante MEMORY_DB_PATH) |
Uso: th-memory [--db <path>] [--json] [--plain] <command> [options] — ayuda por comando mediante th-memory <command> --help.
Banderas globales (cada comando):
| Banderas | Efecto |
|---|---|
--db <path> | usar este archivo SQLite (establece MEMORY_DB_PATH) |
--json | imprimir JSON {ok,data} en lugar de texto plano |
--plain / --no-color | desactivar colores |
-h, --help | mostrar ayuda (global o por comando) |
-V, --version | imprimir versión |
Comandos:
| Comando | Uso |
|---|---|
remember | remember --category <c> --key <k> --value <v|-> — guardar una preferencia (--value - lee desde stdin) |
recall | recall <topic> [--limit <n>] [--highlight] — buscar en la memoria |
forget | forget <id> [--type <t>] — eliminar por id (t: memory|preference|lesson|interaction) |
export | export [--include-interactions] [--filename <n>] — exportar a data/exports/*.json |
import | import (--file <p>|--json <s>) [--apply] [--user-id <id>] — importar copia de seguridad (simulación por defecto) |
stats | stats — estadísticas de memoria |
profile | profile — perfil de usuario destilado |
history | history [--query <q>] [--limit <n>] — buscar prompts pasados (sin consulta = prompts recientes) |
recent | recent [--limit <n>] [--kind <k>] — interacciones recientes (k: prompt|tool_call|error) |
highlight | highlight [text...] -q <topic> [--limit <n>] — resaltar coincidencias de temas (texto vacío = tubería stdin) |
Comportamiento de resaltado (comando highlight y recall --highlight): las coincidencias se envuelven con un subrayado (ESC[4m…ESC[24m) cuando stdout es una TTY con colores habilitados; cuando se canaliza, con --json, o con --plain/--no-color, las coincidencias se envuelven con marcadores [mem]…[/mem] en su lugar.
Ejemplos:
th-memory remember --category coding_pref --key package_manager --value pnpm
th-memory recall pnpm --limit 5
th-memory recall pnpm --highlight
echo "I prefer pnpm for installs" | th-memory highlight -q pnpm
Nota: --value - lee el valor desde stdin (p. ej. echo -n "pnpm" | th-memory remember --category coding_pref --key package_manager --value -).
Instalar con OpenCode
- Fusiona la sección
mcpdeopencode.example.jsonen tuopencode.json(global o a nivel de proyecto)- Importante: establece
MEMORY_DB_PATHal MISMO archivo de base de datos tanto para el servidor como para el plugin (el ejemplo usa<ABSOLUTE_PATH>/th-memory-mcp/data/memory.db), de lo contrario el plugin de captura automática escribe en una base de datos diferente a la que lee la IA - Cómo configurarlo (elige uno):
- defínelo en el
environmentde mcp (ver ejemplo) — cubre solo el servidor MCP - o establécelo como variable de entorno a nivel de sistema/usuario (p. ej.
setx MEMORY_DB_PATH "D:/path/to/memory.db"en Windows) — cubre tanto el servidor como el plugin, ya que el plugin se ejecuta en el mismo proceso que OpenCode
- defínelo en el
- Importante: establece
- Adjunta las reglas de memoria globales — agrega a
opencode.json:
(el contenido de ejemplo de la regla está en"instructions": ["C:/Users/<user>/.config/opencode/memory-protocol.md"]AGENTS.memory.example.md— se puede adjuntar a nivel de proyecto en su lugar) - (Opcional) Implementa el plugin de captura automática: copia
src/plugin/learning-capture.ts→~/.config/opencode/plugins/learning-capture.ts - Reinicia OpenCode (la configuración se carga solo al inicio)
- Prueba: "Recuerda que prefiero pnpm" → abre una nueva sesión y pregunta de nuevo
Uso diario
La IA acepta tanto tailandés como inglés de manera intercambiable — puedes cambiar de idioma en cualquier momento sin aviso.
| Comando de ejemplo | Herramienta / efecto |
|---|---|
| "Recuerda que..." | remember — guardar una preferencia |
| "Resumir memoria" / "destilar memoria" | Destilación inteligente — la IA lee get_recent_interactions, encuentra patrones y guarda conocimientos por sí misma |
| "¿Cómo está mi memoria?" / "estado de memoria" | memory_stats |
| "Exportar memoria" / "respaldar memoria" | export_memory |
| "Buscar historial..." | search_history |
| "Olvidar..." | forget |
Cuidado a largo plazo: ejecuta npm run distill ocasionalmente para resumir estadísticas y podar interacciones de más de 30 días.
Estructura de data/
data/
├── memory.db # SQLite (WAL mode) — main DB (+ .db-wal, .db-shm)
└── exports/ # JSON files from export_memory (writeable only in this dir)
- La ruta de la base de datos se puede sobrescribir mediante la variable de entorno
MEMORY_DB_PATH - todo en
data/está ignorado por git
Benchmark — autoinformado interno (no de terceros)
⚠️ Benchmark autoinformado interno — no es un benchmark de terceros
- interno de muestra pequeña: 180 registros/30 temas (B.recuperación: 30 temas × 5 relevantes + 30 distractores = 180; la ejecución completa también usa subconjuntos de almacenamiento/temporal/contexto de muestra pequeña)
- autoejecución en una sola máquina: máquina de desarrollo única, un solo SO/Node/compilación better-sqlite3 — no entre máquinas, no verificado de forma independiente
- no es un benchmark de terceros: autoinformado, no verificado de forma independiente; no lo compares como si fuera de un evaluador externo
- El conjunto de datos y el arnés están en
repro/(se puede confirmar) ybenchmark/(marco completo, verTH_MEMORY_MCP_BENCHMARK_SPEC.mdybenchmark/README.md).
Dos modos
| Modo | Comando | Datos | Suites | Caso de uso |
|---|---|---|---|---|
| Normal | npm run benchmark | 180 registros / 30 temas | recuperación | verificación rápida (<5s) |
| Pesado | npm run benchmark:heavy | 600 registros / 100 temas + escala de 2k | todos (almacenamiento/recuperación/temporal/contexto/rendimiento/escalabilidad/en frío/ablación) | estrés / regresión |
Reproducir:
npm run build
# Normal — quick
npm run benchmark
npm run benchmark -- --k 10
npm run benchmark -- --out repro/results
# Heavy — full framework, more data
npm run benchmark:heavy
# or custom:
node benchmark/run.mjs --suite all --topics 100 --distractors 100 --scale 2000 --out benchmark/results
Visor — comparar las últimas 3 versiones (tabla + gráficos)
npm run benchmark:viewer
# or: npx serve . -l 3000
# open http://localhost:3000/benchmark/viewer/ or http://localhost:3000/result/viewer.html
El visor carga benchmark/results/history.jsonl, agrupa por versión, toma la última ejecución de las 3 versiones más recientes (p. ej. 2.2.6 / 2.2.7 / 2.2.8) y muestra una tabla resaltada (1 fila por versión) + gráficos de barras para Recall@5 / MRR / NDCG@5 y Latency p95. Los resultados también se guardan por versión en result/v*_benchmark_result.md y benchmark/results/versions/<ver>/.
Última ejecución interna (v2.2.8, en caliente, perfil normal, a2dcbce — no de terceros): Recall@5=0.9060, Precision@5=0.9060, MRR=1, NDCG@5=0.9347 sobre 100 temas/600 registros. Ver result/v2.2.8_benchmark_result.md y repro/README.md para detalles y advertencias (interno, autoejecución en una sola máquina).
Limitaciones conocidas
- Sin cifrado en reposo (texto plano en reposo) —
data/memory.db(modo WAL,better-sqlite3) es un archivo SQLite plano y sin cifrar.100% local & privatesignifica sin exfiltración por nube o red — no significa cifrado en reposo. Cualquier persona con acceso al sistema de archivos (máquina compartida, copia de seguridad, malware, dispositivo robado) puede leer preferencias/lecciones/interacciones en texto plano. Para datos sensibles, usa cifrado de disco completo a nivel de SO (BitLocker / FileVault / LUKS) o una compilación SQLCipher opcional (requiere recompilación nativa y gestión de claves). No se aplica SQLCipher/cifrado en código por defecto ysrc/db/index.tslo documenta explícitamente. - Proceso local de un solo usuario — sin capa de autenticación (Lote B-3) —
userId/sessionId/projectIdson cadenas proporcionadas por el llamador con sin autenticación ni verificación de autorización dentro del servidor. El aislamiento de alcance (recuperación,get_context, recorrido/expansión de grafo,consolidate,link_memory,merge_memory) se aplica solo contra los valores que envía el llamador, por lo que un llamador puede leer o escribir cualquier alcance pasando un id diferente. Esto es adecuado para un proceso local de un solo usuario (un operador,data/memory.dblocal). No compartas un servidor/base de datos entre usuarios que no se confían mutuamente sin una capa de autenticación al frente que autentique a cada llamador y fuerce eluserIdcorrecto (yprojectId/sessionIdpermitidos). No se incorpora ningún sistema de autenticación nuevo en el servidor por diseño — esa capa pertenece al frente de él.
Licencia
MIT © 2026 worakorn-prince
Este proyecto está licenciado bajo la Licencia MIT — consulta el archivo LICENSE para el texto completo.