¿Por qué migrar?
Si usas el servidor MCP Memory de Anthropic, tu knowledge graph vive en un único archivo JSONL. mcp-memory almacena los mismos datos en SQLite con indexación adecuada, soporte de concurrencia y embeddings vectoriales — pero el formato de datos es idéntico.
La tool migrate lee tu archivo JSONL existente e importa cada entidad, observación y relación en la base de datos SQLite. Es idempotente, tolerante a fallos y segura para ejecutar múltiples veces.
:::tip No se elimina ni modifica el archivo JSONL original. La migración solo lee de él. :::
Formato origen: JSONL
El servidor MCP Memory de Anthropic almacena datos en formato JSONL — un objeto JSON por línea. Hay exactamente dos tipos de registro:
Registros de entidad
Una entidad representa un nodo en el knowledge graph con nombre, tipo y una lista de observaciones:
{
"type": "entity",
"name": "Session 2026-03-21",
"entityType": "Session",
"observations": ["Decision: build MCP Memory v2", "Uses FastMCP framework"]
}
Campos obligatorios:
| Campo | Tipo | Descripción |
|---|---|---|
type | string | Debe ser "entity" |
name | string | Identificador único de la entidad |
entityType | string | Tipo de entidad (por defecto "Generic" si se omite) |
observations | string[] | Lista de cadenas de observación (puede estar vacía) |
Registros de relación
Una relación conecta dos entidades con un arco tipado:
{ "type": "relation", "from": "MCP Memory v2", "to": "FastMCP", "relationType": "uses" }
Campos obligatorios:
| Campo | Tipo | Descripción |
|---|---|---|
type | string | Debe ser "relation" |
from | string | Nombre de la entidad origen |
to | string | Nombre de la entidad destino |
relationType | string | Tipo de relación |
Ejemplo de archivo JSONL
Un archivo típico mezcla ambos tipos de registro. Las entidades deben aparecer antes de las relaciones que las referencian:
{"type": "entity", "name": "Project Alpha", "entityType": "Project", "observations": ["Started in March 2026", "Uses Python 3.12"]}
{"type": "entity", "name": "SQLite", "entityType": "Technology", "observations": ["Used for persistence"]}
{"type": "entity", "name": "FastMCP", "entityType": "Framework", "observations": ["MCP server framework"]}
{"type": "relation", "from": "Project Alpha", "to": "SQLite", "relationType": "uses"}
{"type": "relation", "from": "Project Alpha", "to": "FastMCP", "relationType": "built_with"}
:::note El orden de las relaciones importa en la primera ejecución — si una relación referencia una entidad que aún no se ha importado, se omite. Ejecutar la migración una segunda vez captura estas relaciones huérfanas, ya que todas las entidades existirán entonces. :::
Proceso de migración
La migración se ejecuta en cuatro fases secuenciales:
Fase 1: Lectura y parseo
El archivo JSONL se lee línea por línea. Cada línea se parsea como un objeto JSON independiente:
- Si la línea se parsea correctamente, el registro se clasifica como entidad o relación según su campo
type. - Si el parseo JSON falla (línea corrupta, problema de codificación), se registra un warning y la línea se omite. La línea se cuenta en el total de
errors. - Las líneas en blanco se ignoran.
Esta fase es puramente en memoria — no se escribe en la base de datos aún. Los registros parseados se encolan para las siguientes fases.
Fase 2: Importar entidades
Cada registro de entidad se procesa mediante upsert_entity, que usa ON CONFLICT(name) DO UPDATE de SQLite:
- Entidad nueva: se inserta en la tabla
entities. - Entidad existente: las observaciones se fusionan — solo se añaden las observaciones que no existen. El tipo de entidad se actualiza si difiere.
Esto permite ejecutar la migración sobre un archivo que se solapa parcialmente con datos ya existentes en la base de datos.
Fase 3: Importar relaciones
Cada registro de relación se valida antes de la inserción:
- Ambas entidades
fromytodeben existir en la base de datos. - Todos los campos obligatorios (
from,to,relationType) deben estar presentes. - La relación no debe existir ya (restricción
UNIQUEsobre(from_entity, to_entity, relation_type)).
Si alguna comprobación falla, la relación se omite y se cuenta como skipped. Si la relación es válida, se inserta mediante create_relation, que captura IntegrityError en restricciones duplicadas por seguridad.
Fase 4: Generación batch de embeddings
Si el motor de embeddings está disponible (modelo descargado — consulta Primeros Pasos), los embeddings se generan para todas las entidades importadas en un único batch al final de la migración.
Esto es significativamente más eficiente que generar embeddings uno a uno durante la importación. El enfoque batch:
- Agrupa todo el texto de entidades en una única pasada de inferencia ONNX.
- Usa
INSERT OR REPLACEsobrerowid— los embeddings existentes se sobrescriben con vectores nuevos. - Si el motor de embeddings no está disponible, esta fase se omite silenciosamente. La migración se completa correctamente y los embeddings se generarán más tarde cuando las entidades se accedan mediante
search_semantic.
:::caution Si la generación individual de embeddings falla durante el batch (por ejemplo, un error de tokenización en texto malformado), se registran como warnings. La migración no se detiene — las entidades restantes continúan procesándose. :::
Cómo ejecutar la migración
Tienes dos opciones: mediante la tool MCP (recomendada para la mayoría de usuarios) o mediante script Python (para acceso programático).
Opción 1: Mediante tool MCP
Si usas un cliente MCP (OpenCode, Claude Desktop, etc.), llama a la tool migrate con la ruta a tu archivo JSONL:
{
"source_path": "~/.config/opencode/mcp-memory.jsonl"
}
La tool expande ~ al directorio home automáticamente. La ruta debe apuntar a un archivo existente y legible.
La tool retorna un resultado JSON (consulta Formato del resultado más abajo).
Opción 2: Mediante script Python
Para scripting o pipelines de CI, importa la función de migración directamente:
from mcp_memory.storage import MemoryStore
from mcp_memory.migrate import migrate_jsonl
store = MemoryStore()
store.init_db()
result = migrate_jsonl(store, "~/.config/opencode/mcp-memory.jsonl")
print(result)
La función migrate_jsonl acepta la misma ruta con expansión de ~. Retorna un diccionario con los mismos campos que la respuesta de la tool MCP.
También puedes ejecutarlo como una línea desde la raíz del repositorio:
uv run python -c "
from mcp_memory.storage import MemoryStore
from mcp_memory.migrate import migrate_jsonl
store = MemoryStore()
store.init_db()
result = migrate_jsonl(store, '~/.config/opencode/mcp-memory.jsonl')
print(result)
"
Idempotencia
La migración es idempotente: ejecutarla múltiples veces produce el mismo resultado sin duplicar datos. Esto es seguro porque cada operación de escritura incluye un mecanismo de resolución de conflictos:
| Operación | Mecanismo | Efecto en ejecuciones repetidas |
|---|---|---|
| Insertar entidad | ON CONFLICT(name) DO UPDATE | Las entidades existentes se actualizan; las observaciones nuevas se fusionan |
| Añadir observación | Comprobación de existencia antes de insertar | Las observaciones duplicadas se descartan silenciosamente |
| Crear relación | IntegrityError capturado en restricción UNIQUE | Las relaciones duplicadas se ignoran |
| Almacenar embedding | INSERT OR REPLACE sobre rowid | El vector de embedding existente se sobrescribe con uno nuevo |
:::tip Ejecutar la migración dos veces es útil: la primera pasada importa entidades, la segunda pasada captura las relaciones que fallaron porque sus entidades destino estaban definidas más adelante en el archivo. :::
Manejo de errores
La migración está diseñada para ser tolerante a fallos — procesa tantos registros como sea posible en lugar de fallar en el primer error:
| Condición de error | Comportamiento | Contado como |
|---|---|---|
| Línea corrupta (JSON inválido) | Omitida con warning | errors |
Entidad sin campo name | Omitida | skipped |
Relación con campos faltantes (from, to o relationType) | Omitida | skipped |
| Relación que referencia entidad inexistente | Omitida | skipped |
Tipo de registro desconocido (no "entity" ni "relation") | Omitido | skipped |
| Fallo individual de embedding | Registrado como warning, la migración continúa | No se cuenta |
La migración nunca lanza una excepción por fallos de registros individuales. Todos los problemas se capturan en los contadores del resultado.
Formato del resultado
La tool migrate retorna un objeto JSON con cuatro campos:
{
"entities_imported": 32,
"relations_imported": 37,
"errors": 0,
"skipped": 2
}
| Campo | Tipo | Descripción |
|---|---|---|
entities_imported | int | Registros de entidad procesados correctamente (insertados o actualizados) |
relations_imported | int | Relaciones creadas efectivamente en la base de datos |
errors | int | Líneas que fallaron el parseo JSON o lanzaron excepciones inesperadas |
skipped | int | Registros omitidos por campos faltantes, entidades destino inexistentes o tipo desconocido |
:::note
entities_imported incluye entidades que fueron actualizadas (no solo creadas). Si ejecutas la migración dos veces, la segunda ejecución reporta el mismo conteo — cada entidad se procesa, incluso si no se añaden observaciones nuevas.
:::
Verificación post-migración
Tras completar la migración, verifica que los datos se importaron correctamente:
1. Revisar las entidades importadas
Usa search_nodes para verificar las entidades importadas y confirmar que los datos se migraron correctamente:
{
"query": ""
}
2. Probar la búsqueda semántica
Si descargaste el modelo de embeddings, verifica que se generaron los embeddings ejecutando una consulta semántica:
{
"query": "tu término de búsqueda aquí",
"limit": 10
}
Si los resultados incluyen campos limbic_score y distance, los embeddings funcionan. Si obtienes un error sobre el modelo, consulta Primeros Pasos para las instrucciones de descarga.
3. Verificar entidades específicas
Usa open_nodes para verificar entidades individuales por nombre:
{
"names": ["Session 2026-03-21", "Project Alpha"]
}
Confirma que las observaciones se fusionaron correctamente y no se perdió datos.
Escenarios comunes
Migrar desde una instalación predeterminada de Anthropic
La ubicación predeterminada del archivo JSONL de Anthropic MCP Memory depende de tu configuración:
# OpenCode
~/.config/opencode/mcp-memory.jsonl
# Claude Desktop (macOS)
~/Library/Application Support/Claude/claude_memory.jsonl
# Claude Desktop (Linux)
~/.config/Claude/claude_memory.jsonl
Pasa la ruta correcta a la tool migrate o a la función Python.
Migración incremental
Si tu archivo JSONL sigue recibiendo escrituras (por ejemplo, ejecutas ambos servidores en paralelo durante un periodo de transición), puedes ejecutar la migración periódicamente. Al ser idempotente, cada ejecución solo importa entidades y observaciones nuevas que no estaban presentes.
Archivos grandes
La migración procesa el archivo línea por línea — nunca carga el archivo completo en memoria. Un archivo con miles de entidades y relaciones se importará sin problemas. La fase de generación batch de embeddings es la parte más lenta, pero procesa los embeddings en lotes en lugar de todos a la vez.
- Siguiente: Referencia de Tools — parámetros, respuestas y casos extremos para las 19 tools
- Ver también: Primeros Pasos — instalación, configuración y primeros pasos