GraphMem
Un servidor MCP para la gestión de memoria basada en grafos, que permite a la IA crear, recuperar y gestionar entidades de conocimiento y sus relaciones.
Documentación
GraphMem: Servidor MCP de Memoria Basada en Grafos
GraphMem es una aplicación Ruby on Rails que implementa un servidor de Protocolo de Contexto de Modelo (MCP) para la gestión de memoria basada en grafos. Permite a asistentes de IA y otros clientes crear, recuperar, buscar y gestionar entidades de conocimiento y sus relaciones a través de una interfaz estandarizada.
Descripción General
GraphMem proporciona almacenamiento persistente y estructurado para entidades de conocimiento, sus relaciones y observaciones. Está diseñado como un servidor MCP que permite a los asistentes de IA mantener memoria entre sesiones, construir grafos de conocimiento específicos de dominio y referenciar interacciones pasadas de manera efectiva.
Diseño de Usuario Único
GraphMem está diseñado como un servidor de usuario único y red local: un grafo para un propietario implícito, compartido por un puñado de agentes de ese propietario. No existe un modelo de autorización por usuario, deliberadamente — el grafo compartido es el punto central.
El acceso se controla mediante el alcance de red más un token portador compartido opcional. Por defecto, el endpoint MCP acepta solicitudes no autenticadas solo desde rangos de loopback y privados (RFC1918), y nunca puede estar simultáneamente no autenticado y accesible desde una dirección pública. Consulta docs/mcp_access_control.md para la configuración, y establece GRAPH_MEM_MCP_TOKEN antes de exponer el servidor más allá de una LAN de confianza.
Contexto de proyecto por agente: Varios clientes MCP pueden conectarse simultáneamente, siempre que cada uno envíe un valor distinto de X-MCP-Client — el contexto se almacena por id de cliente, por lo que dos agentes que compartan un mismo valor sobrescribirán el alcance del otro. GraphMem detecta este caso y añade un warning a las respuestas de set_context y get_context. Cada agente se identifica en su configuración MCP:
{
"mcpServers": {
"graph_mem": {
"url": "http://localhost:3030/mcp",
"headers": { "X-MCP-Client": "Agent-1" }
}
}
}
El ejemplo anterior asume el uso de la configuración de contenedor, que está fijada al puerto 3030. (APP_PORT está actualmente fijado en Dockerfile y docker-compose.yml).
Usa /mcp para el perfil Streamable HTTP predeterminado de 2025-03-26. Usa
/mcp/readonly para contexto y herramientas de lectura únicamente, o /mcp/maintenance para el
catálogo completo incluyendo operaciones de mantenimiento. El endpoint SSE heredado de 2024-11-05
sigue disponible en /mcp/sse y utiliza el perfil predeterminado.
El servidor también publica los prompts MCP orient, recall y persist. Cada
llamada exitosa a una herramienta incluye la versión de GraphMem, un next_move conciso, y
un banner de contexto cuando el cliente no ha seleccionado un proyecto.
Las 12 herramientas predeterminadas anuncian outputSchema y devuelven structuredContent coincidentes
más texto JSON reflejado para clientes compatibles con versiones anteriores.
El contexto establecido mediante set_context se almacena por client_id en la base de datos y sobrevive a los reinicios del servidor. Los agentes sin el encabezado comparten el bucket de cliente "default" (comportamiento de agente único compatible con versiones anteriores), así que asigna a cada agente su propio valor una vez que ejecutes más de uno.
El encabezado es una clave de alcance cooperativa, no una credencial: un agente puede reclamar cualquier id de cliente, y el token compartido otorga acceso idéntico completo de lectura/escritura a todos los que lo poseen. El aislamiento multiinquilino queda fuera del alcance — si dos personas necesitan memorias separadas, ejecuta dos instancias contra dos bases de datos.
Capacidades clave:
- Búsqueda semántica vectorial mediante soporte VECTOR nativo de MariaDB 11.8 + embeddings de Ollama
- Delimitación de contexto de proyecto — por agente mediante
X-MCP-Client, persistente entre reinicios - Canonicalización de tipos de entidad para prevenir la fragmentación del grafo
- Auto-deduplicación en la creación de entidades
- Búsqueda híbrida que combina tokenización de texto con similitud vectorial (con refuerzo de contexto)
- Despliegue con Docker Compose con soporte de inicio automático
- Arquitectura de embeddings en toda la LAN usando un host Ollama centralizado
Pila Tecnológica
- Ruby: 3.4.1+
- Rails: 8.1.2+
- Implementación MCP: gema fast-mcp con un
GraphMem::McpStreamableHttpTransportpersonalizado que añade soporte Streamable HTTP de 2025-03-26 manteniendo el transporte SSE de 2024-11-05 - Base de datos: MariaDB 11.8+ (se requiere soporte VECTOR)
- Embeddings: Ollama con nomic-embed-text (768 dimensiones)
Características
Reglas y Habilidades
GraphMem incluye reglas orientadas a agentes y una habilidad neutral respecto al proveedor:
Usar GraphMem como un conjunto de herramientas MCP (tu agente habla con un servidor en ejecución):
docs/rules/graph_mem_mcp_rules.md— reglas siempre activas para copiar en el conjunto de reglas de tu agente (destinos de instalación por agente:docs/rules/README.md)docs/rules/general_coding_rules.md— reglas de codificación opcionales e independientes del proyectoskills/graph-mem-mcp-toolset/SKILL.md— habilidad operativa neutral respecto al proveedor (funciona en Cursor, Claude Code, Devin, ...; la copia de.cursor/skills/es un adaptador delgado)
Desarrollar GraphMem en sí mismo (editar este repositorio): consulta AGENTS.md,
docs/development.md y las reglas con alcance de repositorio bajo .cursor/rules/ y
.devin/rules/.
Herramientas MCP
GraphMem expone las siguientes herramientas MCP:
Gestión de Entidades
get_entities-- Recupera una o más entidades con observaciones y proyecciones de relación completas/internassearch-- Búsqueda resumida clasificada, búsqueda de subgrafo proyectado o listado de catálogo paginado
Mutación del Grafo
graph_write-- Crea atómicamente entidades, observaciones y relacionesgraph_edit-- Actualiza atómicamente metadatos de entidad o contenido/ciclo de vida de observacionesgraph_delete-- Elimina, obsoleta o fusiona atómicamente registros del grafo
Las observaciones usan un ciclo de vida active, obsolete o superseded. Las lecturas normales de entidades, el recorrido del grafo, el descubrimiento de relaciones y la búsqueda exponen solo observaciones activas. Usa get_entities(include_obsolete: true) o include_obsolete=true en los listados REST/recurso de observaciones para inspeccionar el historial retenido. Las operaciones explícitas de mantenimiento de limpieza de duplicados aún eliminan permanentemente filas activas redundantes.
Gestión de Relaciones
traverse_graph-- Recorrido acotado de múltiples saltos o consulta directa de relación por endpoint/tipofind_shortest_path-- Camino más corto (por número de saltos) entre dos entidades
Los nombres anteriores de lectura y mutación siguen siendo alias de compatibilidad invocables, pero están
ocultos de tools/list mientras la telemetría mide el uso restante.
Contexto y Flujo de Trabajo
set_context-- Limita operaciones posteriores a un proyecto (porX-MCP-Client)get_context-- Verifica el contexto de proyecto activoclear_context-- Elimina la delimitación de proyectosuggest_merges-- Encuentra posibles entidades duplicadas mediante similitud vectorialdream_state_status-- Reporta el estado de compactación del grafo en segundo plano (ejecutando/pausado/cursor)get_maintenance_reports-- Lee informes de mantenimiento/compactación, incluyendo la colacompaction_review
Utilidades
get_version-- Versión del servidorget_current_time-- Hora del servidor en ISO 8601
Compactación en Estado de Sueño
Un trabajo en segundo plano de estado de sueño (DreamStateCompactionJob, programado mediante Solid Queue recurring.yml) compacta periódicamente el grafo de conocimiento:
- Fase de huérfanos -- adjunta nodos huérfanos de alta confianza a raíces
Projectcoincidentes - Fase de recorrido de árbol -- deduplica observaciones idénticas y auto-fusiona entidades muy similares (distancia coseno < 0.10)
- Cola de revisión -- fusiones de menor confianza y coincidencias de huérfanos se escriben en
maintenance_reports(compaction_review), legible medianteget_maintenance_reports
El trabajo es pausable cooperativamente: las herramientas MCP de mutación solicitan una pausa cuando la compactación está en ejecución, por lo que el tráfico de herramientas en vivo tiene prioridad. Usa dream_state_status para inspeccionar la posición del cursor y estadísticas, y get_maintenance_reports para revisar y ejecutar las sugerencias en cola. Las ejecuciones pausadas se reanudan en el siguiente disparador programado.
Recursos MCP
memory_entities-- Consulta entidades con filtrado, ordenamiento e inclusión de relacionesmemory_observations-- Accede a observaciones con filtrado avanzadomemory_relations-- Consulta relaciones con inclusión bidireccional de entidadesmemory_graph-- Recorridos del grafo desde cualquier entidad
API REST
API REST completa en /api/v1 para integración directa. Documentación Swagger disponible en /api-docs.
Visualización del Grafo
Visualización interactiva del grafo basada en Cytoscape.js en la raíz del servidor (/), con menús contextuales, operaciones de arrastrar y soltar, y funciones de gestión de datos.
Inicio Rápido con Docker
Requisitos previos: Ollama debe estar ejecutándose en el host con al menos un modelo de embeddings descargado:
# Install Ollama (https://ollama.com) then pull the default embedding model
ollama pull nomic-embed-text
El contenedor
appusanetwork_mode: host, por lo que comparte la pila de red del host.localhost:11434alcanza a Ollama sin necesidad de configuración de puente/cortafuegos. La aplicación se vincula directamente al puerto 3030 del host.
# Clone and enter the project
git clone https://github.com/steveoro/graph_mem.git
cd graph_mem
# Copy example config and set your master key
cp .env.example .env
# Edit .env: set RAILS_MASTER_KEY (from config/master.key) and DB_PASSWORD
# Start the stack (MariaDB 11.8 + Rails in production mode)
docker compose up -d
# Seed canonical entity types
docker compose exec app bin/rails db:seed
# Verify Ollama connectivity
docker compose exec app bin/rails embeddings:check
# Backfill embeddings
docker compose exec app bin/rails embeddings:backfill
# Update the container after a repository pull
docker compose down && docker compose up -d --build
La aplicación está disponible en http://localhost:3030. Documentación de la API Swagger en http://localhost:3030/api-docs.
El puerto de la aplicación (3030) está fijado en Dockerfile y docker-compose.yml porque el servicio depende de la red del host para acceder al servicio de embeddings mediante ollama. Esto permite una configuración de contenedor más simple en diferentes máquinas sin recurrir a iptables o manipulación de cortafuegos.
Esta aplicación contenerizada es un servidor de usuario único sin capa de autenticación — está diseñada para ejecutarse localmente en una máquina y/o ser accesible solo a través de una LAN de confianza. No expongas este servicio a la internet pública.
Compartir en LAN
Para permitir que un servidor Ubuntu local que ejecute graph_mem en un contenedor con ollama ejecutándose como servicio para el procesamiento de embeddings, recuerda permitir el tráfico entrante si estás usando ufw (asumiendo que tu LAN local está configurada en 192.168.0.0/24):
sudo ufw allow from 192.168.0.0/24 to any port 3030 proto tcp comment "GraphMem from LAN"
sudo ufw allow from 192.168.0.0/24 to any port 11434 proto tcp comment "Ollama from LAN"
De esta manera, la interfaz de graph_mem será accesible en http://<graph_mem_server_ip>:3030/ mientras que el servidor MCP estará en http://<graph_mem_server_ip>:3030/mcp/sse.
Control de acceso en una LAN compartida
El endpoint MCP acepta solicitudes no autenticadas desde rangos privados por defecto, por lo que cada dispositivo en la LAN tiene acceso completo de lectura/escritura al grafo. Una vez que la red no sea completamente confiable, establece un token compartido en el servidor:
# in .env on the GraphMem host
GRAPH_MEM_MCP_TOKEN=$(openssl rand -hex 32)
GRAPH_MEM_MCP_ALLOWED_IPS=192.168.0.0/24
y agrégalo a cada configuración de cliente junto con el encabezado X-MCP-Client:
"headers": {
"Authorization": "Bearer <GRAPH_MEM_MCP_TOKEN>",
"X-MCP-Client": "cursor-1"
}
Los clientes pueden actualizarse antes que el servidor: mientras no se configure ningún token, el encabezado se ignora, por lo que puedes implementarlo sin tiempo de inactividad. Referencia completa en docs/mcp_access_control.md.
Configuración de Desarrollo Nativo
Para desarrollo local, ejecuta la aplicación de forma nativa con MariaDB en localhost.
-
Requisitos previos:
- Ruby 3.4.1+ (mediante RVM o rbenv)
- MariaDB 11.8+ (para búsqueda vectorial)
- Ollama con un modelo de embeddings
-
Instalar dependencias:
bundle install -
Configuración de la base de datos:
cp config/database.example.yml config/database.yml # Edit config/database.yml with your MariaDB credentials bin/rails db:prepare bin/rails db:seed -
Descargar un modelo de embeddings:
ollama pull nomic-embed-text -
Rellenar embeddings:
bin/rails embeddings:backfill -
Iniciar el servidor de desarrollo:
bin/dev
Configuración del Cliente MCP
Cursor
Edita el mcp.json de tu Cursor:
Opción A -- Transporte Streamable HTTP (recomendado para clientes modernos):
{
"mcpServers": {
"graph_mem": {
"url": "http://localhost:3030/mcp",
"headers": { "X-MCP-Client": "Agent-1" }
}
}
}
Opción B -- Transporte SSE heredado (Docker / clientes antiguos):
{
"mcpServers": {
"graph_mem": {
"url": "http://localhost:3030/mcp/sse"
}
}
}
Opción C -- Transporte stdio (desarrollo nativo / cambios en tiempo real aplicados):
{
"mcpServers": {
"graph_mem": {
"command": "/bin/bash",
"args": ["/absolute/path/to/graph_mem/bin/mcp_graph_mem_runner.sh"],
"env": { "RAILS_ENV": "development" }
}
}
}
Opción D -- stdio mediante Docker:
{
"mcpServers": {
"graph_mem": {
"command": "/bin/bash",
"args": ["/absolute/path/to/graph_mem/bin/docker-mcp"]
}
}
}
Windsurf
Edita el mcp_config.json de tu Windsurf usando el mismo enfoque que el de Cursor. Normalmente el contenedor SSE no presenta ningún problema.
Antigravity / Devin (Streamable HTTP)
GraphMem ahora soporta el transporte Streamable HTTP de 2025-03-26. Apunta estos clientes a la URL base MCP:
{
"mcpServers": {
"graph_mem": {
"url": "http://localhost:3030/mcp",
"headers": { "X-MCP-Client": "Agent-1" }
}
}
}
El endpoint SSE heredado (/mcp/sse) sigue disponible para clientes antiguos.
Asumiendo que graph_mem-app-1 es el nombre del contenedor en ejecución, edita mcp_servers.json:
{
"mcpServers": {
"graph_mem": {
"command": "/usr/bin/docker",
"args": [
"exec",
"-i",
"graph_mem-app-1",
"bash",
"-c",
"'bin/bundle exec ruby bin/mcp_stdio_runner.rb'"
// For development, change env below and replace the command with bash, first arg "-c" and second arg:
// "cd /home/steve/Projects/graph_mem && exec /usr/share/rvm/wrappers/ruby-3.4.1@graph_mem/bundle exec ruby bin/mcp_stdio_runner.rb"
],
"env": {
"RAILS_ENV": "production"
}
}
}
}
Claude Code
Normalmente tanto stdio como SSE deberían funcionar ya que las 3 opciones destacadas anteriormente deberían funcionar.
Edita el mcp_servers.json de tu Claude con la que elijas.
Acceso LAN (Múltiples Máquinas)
Consulta Arquitectura para más detalles.
Ten en cuenta que la versión actual de GraphMem está diseñada específicamente para uso de un solo usuario, es decir, 1 usuario de IA por instalación: actualmente no hay almacenamiento de sesión por conversación, por lo que múltiples agentes de IA que se conecten y usen la misma instancia de GraphMem en ejecución pueden sobrescribir el trabajo de los demás (uno podría restablecer el contexto actual de otro, impidiendo que la "válvula de contexto" funcione como se espera, lo que llevaría a una expansión del contexto).
Pero nada te impide compartir el mismo grafo de memoria generado entre diferentes estaciones de trabajo, siempre que GraphMem sea utilizado por un solo usuario de IA a la vez. O, de manera más realista, implementa GraphMem en un servidor de alto rendimiento y accede a él desde tu estación de trabajo habitual.
Entonces, al ejecutar GraphMem en un servidor local y acceder a él desde otras máquinas en la LAN:
1. Exponer Ollama en el host que ejecuta
Por defecto, Ollama solo escucha en 127.0.0.1. Crea una anulación de drop-in de systemd
(sobrevive a las actualizaciones del paquete Ollama):
sudo mkdir -p /etc/systemd/system/ollama.service.d
echo '[Service]
Environment="OLLAMA_HOST=0.0.0.0"' | sudo tee /etc/systemd/system/ollama.service.d/override.conf
sudo systemctl daemon-reload
sudo systemctl restart ollama
Verifica que esté vinculado a todas las interfaces:
ss -tlnp | grep 11434
# Should show *:11434 instead of 127.0.0.1:11434
2. Configurar OLLAMA_URL
En el host que ejecuta GraphMem, OLLAMA_URL=http://localhost:11434 (el valor predeterminado) funciona
porque el contenedor app usa redes del host.
Si Ollama se ejecuta en otra máquina diferente, establece en .env:
OLLAMA_URL=http://<ollama-host-ip>:11434
3. Conectar clientes MCP desde otras máquinas de la LAN
Usa el endpoint HTTP Streamable para clientes modernos:
{ "url": "http://<workstation-ip>:3030/mcp" }
El endpoint SSE heredado sigue disponible:
{ "url": "http://<workstation-ip>:3030/mcp/sse" }
Gestión de Embeddings
Panel del operador
Inicia sesión en /operator/login, luego abre Embeddings desde el panel principal o ve a /operator/embeddings. La página muestra cobertura, estado del índice, configuración resuelta (con insignias de fuente: AppSettings / ENV / Default), prueba de conexión, trabajos de backfill/regeneración y acciones de agregar/eliminar índice ANN.
La configuración del servicio de embeddings se encuentra en System Settings → Embeddings (/operator/settings?tab=embeddings). La configuración se resuelve en este orden:
| Prioridad | Fuente |
|---|---|
| 1 | AppSettings (interfaz del operador) — cadena vacía o dimensiones 0 difieren a ENV |
| 2 | Variables de entorno (OLLAMA_URL, EMBEDDING_MODEL, EMBEDDING_PROVIDER, EMBEDDING_DIMS) |
| 3 | Valores predeterminados integrados (http://localhost:11434, nomic-embed-text, ollama, 768) |
Las variables ENV siguen siendo la opción correcta para Docker y manifiestos de implementación; la interfaz las anula cuando se establecen valores. Habilita backfill programado en la configuración para ejecutar EmbeddingScheduledBackfillJob diariamente (consulta config/recurring.yml).
Consulta docs/operator/embeddings.md para el flujo de trabajo recomendado del operador.
Prueba de conectividad con Ollama
Antes de hacer backfill o regenerar embeddings, verifica que la aplicación pueda alcanzar tu instancia de Ollama:
# Docker
docker compose exec app bin/rails embeddings:check
# Native
bin/rails embeddings:check
Esto envía un único embedding de prueba a través de EmbeddingService usando la configuración resuelta (AppSettings → ENV → valores predeterminados). Informa la configuración resuelta, la latencia de respuesta y las dimensiones del vector — la misma ruta de código exacta utilizada por backfill y regenerate.
Para una verificación de nivel más bajo, curl está disponible dentro del contenedor de producción (las redes del host
significan que localhost llega a Ollama directamente):
# Verify Ollama is reachable and list available models
docker compose exec app curl -sf http://localhost:11434/api/tags
# Test a raw embedding request
docker compose exec app curl -sf http://localhost:11434/api/embed \
-d '{"model":"nomic-embed-text","input":"hello"}'
Tareas Rake
| Tarea | Descripción |
|---|---|
embeddings:check | Prueba de humo de conectividad y configuración de Ollama |
embeddings:backfill | Generar embeddings para registros que carecen de ellos |
embeddings:regenerate | Recalcular todos los embeddings en su lugar (por ejemplo, después de cambiar de modelo) |
embeddings:add_indexes | Agregar VECTOR INDEX (HNSW, coseno) después de que todas las filas estén pobladas |
embeddings:drop_indexes | Eliminar índices y revertir columnas a anulables |
Cambio de modelos de embeddings
Para cambiar el modelo (por ejemplo, de nomic-embed-text a uno diferente):
- Descarga el nuevo modelo en el host de Ollama:
ollama pull <model-name> - Actualiza el modelo (y las dimensiones si son diferentes) en System Settings → Embeddings o mediante
EMBEDDING_MODEL/EMBEDDING_DIMSen.env - Verifica la conectividad:
bin/rails embeddings:checko el botón Test connection del operador - Recalcula todos los vectores:
bin/rails embeddings:regenerateo la acción Regenerate all del operador
Copia de seguridad y restauración de la base de datos
Las copias de seguridad se gestionan a través de System Settings (/operator/settings, inicio de sesión de sesión) y tareas rake. Los volcados tienen marca de tiempo, están limitados al entorno y se conservan según backup_keep_max:
# Dump current database to <backup_folder>/<YYYYMMDDHHMM>_<env>.sql.bz2
bin/rails db:dump
# List backups for the current environment
bin/rails db:list_backups
# Restore from newest backup, or a specific file
bin/rails db:restore
FILE=202601011200_production.sql.bz2 bin/rails db:restore
Las copias de seguridad programadas se ejecutan a través de Solid Queue (DatabaseBackupJob) cuando Enable scheduled backups está activado en System Settings. Programa de producción: 1pm y 5pm GMT (config/recurring.yml). Usa el panel Jobs en /operator/jobs (misma sesión de operador) para inspeccionar el estado de la cola.
Inicia sesión en /operator/login. Credenciales de operador predeterminadas: operator / changeme (anula con OPERATOR_USERNAME / OPERATOR_PASSWORD o credenciales de Rails bajo operator:).
Variables de entorno
| Variable | Predeterminado | Descripción |
|---|---|---|
OLLAMA_URL | http://localhost:11434 | URL base de la API de Ollama (anulada por AppSettings embedding_url cuando se establece) |
EMBEDDING_MODEL | nomic-embed-text | Nombre del modelo de Ollama para embeddings |
EMBEDDING_PROVIDER | ollama | ollama o openai_compatible |
EMBEDDING_DIMS | 768 | Dimensiones del vector (deben coincidir con el modelo) |
DB_PASSWORD | my_password | Contraseña raíz de MariaDB |
DB_NAME | graph_mem | Nombre de la base de datos |
DB_PORT | 3307 | Puerto del host para MariaDB (Docker) |
RAILS_MASTER_KEY | -- | Clave de credenciales de Rails (requerida para Docker) |
DATABASE_URL | -- | URL completa de la base de datos (anula la configuración individual de la base de datos) |
DB_BACKUP_HOST_PATH | ./db/backup | Ruta completa a la carpeta de copias de seguridad de la base de datos (el valor predeterminado no es válido: docker-compose no expandirá caracteres especiales) |
OPERATOR_USERNAME | operator | Nombre de usuario de inicio de sesión del operador para el panel web |
OPERATOR_PASSWORD | changeme | Contraseña de inicio de sesión del operador (cambiar en producción) |
Documentación
- Guía de embeddings del operador
- Referencia de herramientas MCP
- Referencia de configuración de la aplicación
- Arquitectura
- Guía de desarrollo
- Solución de problemas
- Recurso de entidad de memoria
- Recurso de observación de memoria
- Recurso de relación de memoria
- Recurso de grafo de memoria
Contribuciones
Las solicitudes de extracción son bienvenidas. Para cambios importantes, abre primero un issue para discutir lo que te gustaría cambiar. Asegúrate de actualizar las pruebas según corresponda. Las solicitudes de extracción sin casos de prueba adecuados no serán aceptadas.
Licencia
El proyecto está disponible como código abierto bajo los términos de la Licencia LGPL-3.0.