Logseq MCP Server

Interactúa con tu base de conocimiento de Logseq para crear páginas, gestionar bloques y organizar información de manera programática.

Documentación

Servidor MCP de Logseq

Convierte tu grafo de Logseq en memoria y espacio de trabajo para agentes de IA. Un servidor de Protocolo de Contexto de Modelo para Logseq con escrituras limitadas por seguridad, un rastro de auditoría en tu diario diario y consultas verificadas expuestas como herramientas. Construido sobre FastMCP (la API de alto nivel del paquete oficial mcp).

PyPI Python 3.11+ License: MIT

Logseq Server MCP server

Está dirigido a la versión de archivo/Markdown ("OG") de Logseq — y los archivos de texto plano son parte de por qué un grafo es una buena memoria para agentes: sincronizable con git, buscable con grep, duradero, sin bloqueo de proveedor. La versión más nueva de base de datos (SQLite) cambió el esquema subyacente; algunos métodos pueden comportarse de manera diferente allí.

Por qué

Los agentes necesitan memoria duradera, y tú ya mantienes una — tu grafo. La pieza que falta es un acceso en el que puedas confiar: un agente debería leer ampliamente y escribir de manera útil, pero nunca tocar lo que no debería — y nunca hacer nada que no puedas ver. Tres decisiones de diseño lo hacen posible:

  • Escrituras limitadas por espacio de nombres. Los agentes escriben solo bajo su propio prefijo (byAgent/ por defecto), más un canal deliberadamente estrecho entre espacios de nombres que no puede cambiar nada más que el marcador de TODO/DOING/DONE de una tarea. Las páginas en la lista negra están ocultas y redactadas de cada lectura.
  • Un rastro de auditoría en tu diario diario. Cada escritura exitosa añade una línea como 22:30 [[byAgent]] wrote [[byAgent/readingList/...]] al diario de hoy — revisar el trabajo de tus agentes se convierte en parte de una rutina matutina que ya tienes.
  • Consultas verificadas como herramientas. Envía Datalog conocido y correcto desde la configuración como herramientas con nombre (query_week_plan, …), para que los agentes no compongan datascript a mano y los modelos más baratos sigan siendo fiables.

Cómo lo uso

Ejecuto una pequeña flota de agentes de Claude Code con este servidor en un Mac mini siempre encendido, contra mi grafo personal en vivo:

  • Investigación nocturna. Un enlace se deja caer en la lista de lectura desde el teléfono; por la noche un agente lo reclama (status:: researching), lee el artículo — o clona superficialmente y lee el repositorio — escribe un resumen estructurado en la página y lo cambia a read.
  • Informe matutino. A las 08:30 un modelo pequeño arma un panel de una página — qué se leyó durante la noche, progreso del plan semanal, tareas actuales NOW/DOING — y envía una sola notificación push.
  • Un diario para todos. Las tareas del humano y las líneas de auditoría de los agentes se intercalan en la misma nota diaria:

A daily note: human tasks and agent audit lines side by side

Las páginas que escribe el investigador — propiedades, resumen, relevancia — enlazan directamente con el resto del grafo:

A research page written by the nightly agent

flowchart LR
    A[AI agents] -- MCP tools --> S[logseq-mcp]
    S -- HTTP API --> L[Logseq graph]
    S -. audit line per write .-> J[daily journal]
    Y((you)) --> L
    Y -- morning review --> J

Requisitos

  • Un Logseq en ejecución con el servidor de API HTTP local habilitado (Configuración → Funciones → Servidor de APIs HTTP, luego inícialo desde el menú 🔌).
  • Un token de autorización creado en la configuración del servidor de API HTTP.

Uso

Claude Code

Local (stdio), token desde el entorno:

claude mcp add logseq --scope user --env LOGSEQ_API_TOKEN=<YOUR_TOKEN> -- uvx mcp-server-logseq

O apúntalo a una instancia remota a través de Streamable HTTP (cómo el teléfono y las sesiones remotas llegan a un host sin cabeza — ver Transportes):

claude mcp add logseq --scope user --transport http http://<host>:8000/mcp \
  --header "Authorization: Bearer <LOGSEQ_MCP_HTTP_TOKEN>"

Claude Desktop

{
  "mcpServers": {
    "logseq": {
      "command": "uvx",
      "args": ["mcp-server-logseq"],
      "env": {
        "LOGSEQ_API_TOKEN": "<YOUR_TOKEN>",
        "LOGSEQ_API_URL": "http://127.0.0.1:12315"
      }
    }
  }
}

Configuración

FuenteTokenURL
EntornoLOGSEQ_API_TOKENLOGSEQ_API_URL (por defecto http://localhost:12315)
Indicador de CLI--api-key--url

El token se lee del entorno o de --api-key; nunca se almacena en código. Se admite un archivo .env (ver .env.example).

Archivo de configuración (opcional)

El comportamiento más allá de los valores predeterminados se establece en un archivo TOML — ruta desde LOGSEQ_MCP_CONFIG (por defecto ~/.config/logseq-mcp/config.toml). Las consultas personalizadas viven en archivos EDN junto a él. El servidor funciona bien sin archivo de configuración (valores predeterminados seguros de solo lectura); ver examples/config.toml para un ejemplo completo anotado.

SecciónOpciones clave
[read]resolve_depth — qué tan profundo expandir ((block refs))
[write]agent_write_prefix (por defecto byAgent), allow_agents_write_any
[search]files_path — carpeta del grafo; configúrala para usar el backend de ripgrep
[blacklist]pages — páginas (y subpáginas) para ocultar y redactar en todas partes
[tasks]allow_status_change — compuerta para set_task_status
[audit_log]enabled — registra escrituras en el diario de hoy
[worklog]enabled, namespace, root_block, exclude, agent_namespace, agent_exclude — el canal de registro de trabajo
[queries.<name>]una consulta con nombre: file/en línea query, register_as_tool, …

Los secretos y la URL de la API permanecen en el entorno, nunca en este archivo.

Transportes

Por defecto, el servidor se ejecuta sobre stdio (para Claude Desktop y otros clientes locales). También hay un transporte Streamable HTTP disponible para uso remoto/en red (por ejemplo, un cliente de teléfono):

LOGSEQ_MCP_HTTP_TOKEN=<client-secret> \
  mcp-server-logseq --transport streamable-http --host 0.0.0.0 --port 8000
# MCP endpoint: http://<host>:8000/mcp

Variables de entorno: LOGSEQ_MCP_TRANSPORT, LOGSEQ_MCP_HOST, LOGSEQ_MCP_PORT, LOGSEQ_MCP_HTTP_TOKEN (o --http-token).

Autenticación

El transporte Streamable HTTP requiere un token de portador: cada solicitud debe enviar Authorization: Bearer <LOGSEQ_MCP_HTTP_TOKEN>, o recibe 401. El servidor se niega a iniciar en este modo sin un token configurado. Ten en cuenta que este es un secreto distinto de LOGSEQ_API_TOKEN:

SecretoDirección
LOGSEQ_API_TOKENeste servidor → Logseq
LOGSEQ_MCP_HTTP_TOKENcliente (teléfono) → este servidor

⚠️ Un token de portador sobre HTTP simple solo es seguro en un canal ya cifrado. No expongas el puerto sin procesar a Internet abierto. El camino fácil para un host doméstico/sin cabeza es Tailscale: instálalo en el host y en el cliente, y llega a http://<host>.<tailnet>.ts.net:8000/mcp a través del túnel cifrado — sin dominios, nginx ni certificados. (tailscale serve puede agregar TLS si quieres https://.)

Docker

Compila una vez:

docker build -t logseq-mcp .

Prueba rápida (efímero — --rm elimina el contenedor al detenerse):

docker run --rm -p 8000:8000 \
  -e LOGSEQ_API_TOKEN=<logseq-token> \
  -e LOGSEQ_MCP_HTTP_TOKEN=<client-secret> \
  -e TZ=Europe/Moscow \
  logseq-mcp

Implementación persistente (por ejemplo, un Mac mini sin cabeza) — ejecuta una vez; --restart lo trae de vuelta después de reinicios:

docker run -d --name logseq-mcp --restart unless-stopped -p 8000:8000 \
  -e LOGSEQ_API_TOKEN=<logseq-token> \
  -e LOGSEQ_MCP_HTTP_TOKEN=<client-secret> \
  -e TZ=Europe/Moscow \
  -e LOGSEQ_MCP_CONFIG=/cfg/config.toml \
  -v /path/to/config-dir:/cfg:ro \
  -v "/path/to/your/graph:/graph:ro" \
  logseq-mcp
  • -v .../config-dir:/cfg — carpeta que contiene tu config.toml (+ queries/, rules/); configura files_path = "/graph" en ella para habilitar la búsqueda de archivos. Omite tanto el montaje como LOGSEQ_MCP_CONFIG para ejecutar con valores predeterminados.
  • -v .../graph:/graph — tu carpeta de grafo de Logseq (solo lectura), para búsqueda de archivos.
  • -e TZ=<zone> — hora local para marcas de tiempo del registro de auditoría (la imagen incluye tzdata; el reloj es UTC de lo contrario).

El contenedor sirve Streamable HTTP en el puerto 8000 y habla con un Logseq que se ejecuta en el host. En Docker Desktop (macOS/Windows), el LOGSEQ_API_URL=http://host.docker.internal:12315 predeterminado ya apunta al host; en Linux agrega --add-host=host.docker.internal:host-gateway (o configura LOGSEQ_API_URL con la IP del host). Asegúrate de que el servidor de API HTTP de Logseq esté ejecutándose y escuchando.

Herramientas

Toda la salida de lectura se normaliza a una forma JSON plana y se pasa por la lista negra. Las lecturas resuelven ((block refs)) sin pérdida (el uuid/status del bloque resuelto se conserva para que puedas actuar sobre él). Los resultados salen como JSON compacto, y un bloque lleva solo los campos que tiene: los vacíos se omiten, y raw_content aparece solo cuando difiere de text — en un diario ocupado eso es un tercio de la forma indentada y completamente claveada.

Buscar

  • search — búsqueda de texto completo sobre el contenido de bloques (query, regex?, limit?, case_sensitive?, exclude_journals?). Usa ripgrep sobre files_path cuando está configurado; de lo contrario, una coincidencia de contenido datascript.
  • find_tasks — bloques de tareas por markers?, tag?, under_tag? (descendiente), page?, priority?, limit?.
  • list_pages — nombres de páginas bajo un espacio de nombres prefix? (depth? limita niveles). Descubre las páginas hijas de un espacio de nombres, que son páginas separadas que el read_page de un padre no mostrará. Solo estructura, no contenido de bloques.
  • custom_query — ejecuta una consulta con nombre desde la configuración (name, inputs?).
  • list_custom_queries — lista las consultas configuradas.
  • datascript_query — ejecuta una consulta Datalog sin procesar (query, inputs?, rules?).

Guía

  • get_logseq_guide — devuelve la guía autorizada para consultar/escribir este grafo (errores verificados de Datalog: nombres en minúsculas, descendientes de prefijo, tipos de marcador y día de diario, etiquetas vs referencias, alcance de lectura/escritura). Una única fuente de verdad ubicada junto con el servidor, para que los agentes no vuelvan a derivar (y malderivar) el comportamiento.

Leer

  • read_page — una página como árbol de bloques normalizado (page, depth?). Una fecha YYYY-MM-DD lee el diario de ese día, sea cual sea el formato de título del grafo; una página que no existe es un error en lugar de un árbol vacío.
  • read_block — un bloque y sus hijos (uuid, depth?).

Escribir (solo espacio de nombres de agente)

  • write_note — crear/añadir/reemplazar una página bajo agent_write_prefix (subpath, content?, mode?, properties?).
  • set_page_properties — configurar/eliminar propiedades de página (subpath, properties; un valor null elimina una).
  • edit_block — reemplazar el contenido de un bloque (uuid, old_content, new_content). Se aplica leer-antes-de-escribir: la edición se rechaza a menos que old_content coincida con el contenido actual exacto del bloque. Solo espacio de nombres de agente.

Tareas

  • create_task — crear un bloque de tarea en el espacio de nombres del agente (title, agent, project?, marker?, priority?, tags?, plan_page?, blocks_on?, on_page?). La única forma de crear tareas — write_note rechaza contenido que comienza con un marcador de tarea.
  • set_task_status — cambiar solo el marcador de una tarea (uuid, status); controlado por [tasks].allow_status_change.

Registro de trabajo (diario de hoy; [worklog].enabled)

Un agente que hace trabajo debería poder decirlo donde se registra el resto del trabajo — el diario — en la misma forma que un humano mantiene a mano:

#_worklog
  #_work/dynamo
    ((6a9eb940-758e-4966-a31d-f91e79c35f42))
      17:50 #_agents/claude/work-scout told how to update
  • list_work_projects — el conjunto cerrado de proyectos bajo los cuales se puede archivar una nota (los hijos directos de [worklog].namespace, menos exclude).
  • list_agents — el conjunto cerrado de nombres con los que se puede firmar una nota, como <runtime>/<name>: las páginas exactamente dos niveles debajo del registro de agentes [worklog].agent_namespace (por defecto _agents), desde cualquier tiempo de ejecución — uno nuevo (_agents/codex/...) no necesita configuración.
  • add_journal_note — añadir HH:MM #<agent> <text> al diario de hoy bajo un proyecto (text, work, agent, task?), anidado bajo un ((ref)) cuando se da una tarea.
  • get_worklog_setup_template — la sección de registro de trabajo para el archivo de instrucciones de un agente (CLAUDE.md, AGENTS.md): qué tarea registrar, cuándo mover su estado, cómo se ve una entrada. Se llama solo cuando el usuario pide configurarlo — "agrega el registro de trabajo a CLAUDE.md" en cualquier sesión es suficiente. La plantilla es worklog_setup.md.

La firma va en línea en la nota, no como un nivel de agrupación: varios agentes registrando contra un proyecto lo dividirían en subárboles paralelos, cada uno con su propia cronología. Ten en cuenta que el servidor no puede autenticar al llamante — cada sesión presenta el mismo token de portador — por lo que agent es una convención de honestidad validada contra una lista, no una identidad. Detecta un error tipográfico, no una suplantación. Lo que la lista SÍ puede prometer es que los agentes no pueden agregarse a sí mismos. Dos reglas sostienen esa línea. El registro vive fuera del prefijo de escritura de los agentes, por lo que write_note no puede crear una página allí — el servidor se niega a iniciar si está configurado dentro. Y solo cuentan las páginas que tienen un archivo: escribir [[_agents/claude/x]] en cualquier nota hace que Logseq cree una página de solo referencia, lo que de otro modo sería suficiente para registrar un nombre. Por lo tanto, registrar un agente significa crear su página, a mano, en Logseq.

Cada encabezado se reutiliza solo mientras sigue siendo el último bloque en su nivel: el root_block entre los bloques de nivel superior del diario, un grupo de proyecto dentro de la raíz, un ancla de tarea dentro de su grupo. Un diario es cronológico, y un encabezado reutilizado dondequiera que esté sigue acumulando notas posteriores: una raíz abierta por la mañana mostraría una nota de la tarde por encima de las líneas de la tarde que la precedieron, y con dos agentes en dos proyectos una nota se uniría al grupo anterior de su proyecto, por encima de la línea posterior del otro proyecto. Una vez que cualquier otra cosa aterriza después de un encabezado, la siguiente nota abre uno nuevo — así el día se lee en el orden en que ocurrieron las cosas, a costa de encabezados repetidos cuando el trabajo se intercala.

Este es el único canal que escribe fuera de agent_write_prefix, por lo que intercambia el confinamiento de rutas por un contrato estricto: solo añadir, solo el diario de hoy, todo lo que crea vive bajo un root_block, work debe venir del enum, task debe ser un bloque de tarea existente, y el servidor sella la hora (un llamador no puede pasar una, así que un agente reanudado no puede registrar un reloj recordado). El texto que comienza con un marcador de tarea se rechaza — use create_task.

Dinámico

  • query_<name> — cada consulta de configuración con register_as_tool = true se expone como su propia herramienta.

Desarrollo

git clone https://github.com/dailydaniel/logseq-mcp.git
cd logseq-mcp
cp .env.example .env   # fill in LOGSEQ_API_TOKEN
uv sync
uv run mcp-server-logseq

Inspeccione con el Inspector MCP:

npx @modelcontextprotocol/inspector uv --directory . run mcp-server-logseq

Licencia

MIT