Logseq MCP Server
Interaja com sua base de conhecimento do Logseq para criar páginas, gerenciar blocos e organizar informações de forma programática.
Documentação
Servidor MCP do Logseq
Transforme seu grafo do Logseq em memória e espaço de trabalho para agentes de IA. Um
servidor Model Context Protocol para
Logseq com gravações com escopo de segurança, trilha de auditoria no seu
diário diário e consultas verificadas expostas como ferramentas. Construído sobre FastMCP (a
API de alto nível do pacote oficial mcp).
Tem como alvo a versão arquivo/Markdown ("OG") do Logseq — e arquivos de texto simples fazem parte do motivo pelo qual um grafo é uma boa memória para agentes: sincronizável com git, pesquisável, durável, sem aprisionamento. A versão mais nova com banco de dados (SQLite) mudou o esquema subjacente; alguns métodos podem se comportar de forma diferente lá.
Por quê
Agentes precisam de memória durável, e você já mantém uma — seu grafo. A peça que falta é um acesso em que você possa confiar: um agente deve ler amplamente e gravar de forma útil, mas nunca tocar no que não deveria — e nunca fazer nada que você não possa ver. Três escolhas de design tornam isso possível:
- Gravações com escopo de namespace. Agentes gravam apenas sob seu próprio prefixo
(
byAgent/por padrão), além de um canal deliberadamente estreito entre namespaces que não pode mudar nada além do marcadorTODO/DOING/DONEde uma tarefa. Páginas na lista negra ficam ocultas e são redigidas em todas as leituras. - Trilha de auditoria no seu diário diário. Toda gravação bem-sucedida acrescenta uma
linha como
22:30 [[byAgent]] wrote [[byAgent/readingList/...]]ao diário de hoje — revisar o trabalho dos seus agentes vira parte de uma rotina matinal que você já tem. - Consultas verificadas como ferramentas. Envie Datalog conhecidamente bom a partir da configuração como ferramentas
nomeadas (
query_week_plan, …), para que agentes não componham datascript manualmente e modelos mais baratos continuem confiáveis.
Como eu uso
Eu executo uma pequena frota de agentes do Claude Code com este servidor em um Mac mini sempre ligado, contra meu grafo pessoal ativo:
- Pesquisa noturna. Um link é deixado na lista de leitura pelo celular; à
noite um agente o reivindica (
status:: researching), lê o artigo — ou faz um clone superficial e lê o repositório — grava um resumo estruturado na página e o muda pararead. - Briefing matinal. Às 08:30 um modelo pequeno monta um painel de uma página — o que foi lido durante a noite, progresso do plano semanal, tarefas atuais NOW/DOING — e envia uma única notificação push.
- Um diário para todos. As tarefas do humano e as linhas de auditoria dos agentes se intercalam na mesma nota diária:
As páginas que o pesquisador grava — propriedades, resumo, relevância — conectam-se diretamente ao restante do grafo:
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
- Um Logseq em execução com o servidor de API HTTP local habilitado (Configurações → Recursos → Servidor de APIs HTTP, depois inicie-o no menu 🔌).
- Um token de autorização criado nas configurações do servidor de API HTTP.
Uso
Claude Code
Local (stdio), token a partir do ambiente:
claude mcp add logseq --scope user --env LOGSEQ_API_TOKEN=<YOUR_TOKEN> -- uvx mcp-server-logseq
Ou aponte para uma instância remota via Streamable HTTP (como sessões do celular e remotas alcançam um host sem cabeça — veja Transports):
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"
}
}
}
}
Configuração
| Fonte | Token | URL |
|---|---|---|
| Ambiente | LOGSEQ_API_TOKEN | LOGSEQ_API_URL (padrão http://localhost:12315) |
| Sinalizador de CLI | --api-key | --url |
O token é lido do ambiente ou de --api-key; ele nunca é armazenado em
código. Um arquivo .env é suportado (veja .env.example).
Arquivo de configuração (opcional)
O comportamento além dos padrões é definido em um arquivo TOML — caminho a partir de
LOGSEQ_MCP_CONFIG (padrão ~/.config/logseq-mcp/config.toml). Consultas personalizadas
ficam em arquivos EDN ao lado dele. O servidor funciona bem sem arquivo de configuração (padrões
seguros, principalmente de leitura); veja examples/config.toml para um
exemplo completo anotado.
| Seção | Opções principais |
|---|---|
[read] | resolve_depth — quão profundo expandir ((block refs)) |
[write] | agent_write_prefix (padrão byAgent), allow_agents_write_any |
[search] | files_path — pasta do grafo; defina-a para usar o backend ripgrep |
[blacklist] | pages — páginas (e subpáginas) para ocultar e redigir em todos os lugares |
[tasks] | allow_status_change — portão para set_task_status |
[audit_log] | enabled — registra gravações no diário de hoje |
[worklog] | enabled, namespace, root_block, exclude, agent_namespace, agent_exclude — o canal de registro de trabalho |
[queries.<name>] | uma consulta nomeada: file/inline query, register_as_tool, … |
Segredos e a URL da API permanecem no ambiente, nunca neste arquivo.
Transports
Por padrão, o servidor roda sobre stdio (para Claude Desktop e outros clientes locais). Um transport Streamable HTTP também está disponível para uso remoto/em rede (por exemplo, um cliente de celular):
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
Variáveis de ambiente: LOGSEQ_MCP_TRANSPORT, LOGSEQ_MCP_HOST, LOGSEQ_MCP_PORT,
LOGSEQ_MCP_HTTP_TOKEN (ou --http-token).
Autenticação
O transport Streamable HTTP exige um token de portador: toda solicitação deve
enviar Authorization: Bearer <LOGSEQ_MCP_HTTP_TOKEN>, ou recebe 401. O
servidor se recusa a iniciar neste modo sem um token definido. Observe que este é um
segredo distinto de LOGSEQ_API_TOKEN:
| Segredo | Direção |
|---|---|
LOGSEQ_API_TOKEN | este servidor → Logseq |
LOGSEQ_MCP_HTTP_TOKEN | cliente (celular) → este servidor |
⚠️ Um token de portador sobre HTTP simples só é seguro em um canal já criptografado. Não exponha a porta bruta à internet aberta. O caminho fácil para um host doméstico/sem cabeça é Tailscale: instale-o no host e no cliente, e alcance
http://<host>.<tailnet>.ts.net:8000/mcppelo túnel criptografado — sem domínios, nginx ou certificados. (tailscale servepode adicionar TLS se você quiserhttps://.)
Docker
Compile uma vez:
docker build -t logseq-mcp .
Teste rápido (efêmero — --rm remove o contêiner ao parar):
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
Implantação persistente (por exemplo, um Mac mini sem cabeça) — execute uma vez; --restart o traz
de volta após reinicializações:
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— pasta que contém seuconfig.toml(+queries/,rules/); definafiles_path = "/graph"nela para habilitar a busca de arquivos. Omita tanto a montagem quantoLOGSEQ_MCP_CONFIGpara executar com os padrões.-v .../graph:/graph— sua pasta do grafo do Logseq (somente leitura), para busca de arquivos.-e TZ=<zone>— hora local para carimbos de data/hora do registro de auditoria (a imagem incluitzdata; o relógio é UTC caso contrário).
O contêiner serve Streamable HTTP na porta 8000 e fala com um Logseq em execução
no host. No Docker Desktop (macOS/Windows), o padrão
LOGSEQ_API_URL=http://host.docker.internal:12315 já aponta para o host;
no Linux, adicione --add-host=host.docker.internal:host-gateway (ou defina
LOGSEQ_API_URL para o IP do host). Certifique-se de que o servidor de API HTTP do Logseq esteja em execução
e ouvindo.
Ferramentas
Toda saída de leitura é normalizada para uma forma JSON plana e passa pela
lista negra. Leituras resolvem ((block refs)) sem perda (o bloco resolvido mantém
uuid/status para que você possa agir sobre ele). Os resultados saem como JSON compacto, e um
bloco carrega apenas os campos que possui: os vazios são omitidos, e raw_content
aparece apenas quando difere de text — em um diário movimentado, isso é um terço da
forma indentada e totalmente chaveada.
Encontrar
- search — busca de texto completo sobre o conteúdo dos blocos (
query,regex?,limit?,case_sensitive?,exclude_journals?). Usa ripgrep sobrefiles_pathquando definido; caso contrário, uma correspondência de conteúdo datascript. - find_tasks — blocos de tarefas por
markers?,tag?,under_tag?(descendente),page?,priority?,limit?. - list_pages — nomes de páginas sob um namespace
prefix?(depth?limita níveis). Descobre as páginas filhas de um namespace, que são páginas separadas que oread_pagede um pai não mostrará. Apenas estrutura, não conteúdo de blocos. - custom_query — executa uma consulta nomeada da configuração (
name,inputs?). - list_custom_queries — lista as consultas configuradas.
- datascript_query — executa uma consulta Datalog bruta (
query,inputs?,rules?).
Guia
- get_logseq_guide — retorna o guia autoritativo para consultar/gravar neste grafo (pegadinhas verificadas de Datalog: nomes em minúsculas, descendentes de prefixo, marcador e tipos de dia de diário, tags vs refs, escopo de leitura/gravação). Uma única fonte de verdade localizada junto ao servidor, para que agentes não rederivem (e derivem errado) o comportamento.
Ler
- read_page — uma página como uma árvore de blocos normalizada (
page,depth?). Uma dataYYYY-MM-DDlê o diário daquele dia, qualquer que seja o formato de título do grafo; uma página que não existe é um erro, não uma árvore vazia. - read_block — um bloco e seus filhos (
uuid,depth?).
Gravar (somente namespace do agente)
- write_note — cria/acrescenta/substitui uma página sob
agent_write_prefix(subpath,content?,mode?,properties?). - set_page_properties — define/remove propriedades de página (
subpath,properties; um valornullremove uma). - edit_block — substitui o conteúdo de um bloco (
uuid,old_content,new_content). Ler antes de gravar é aplicado: a edição é rejeitada a menos queold_contentcorresponda ao conteúdo atual exato do bloco. Somente namespace do agente.
Tarefas
- create_task — cria um bloco de tarefa no namespace do agente (
title,agent,project?,marker?,priority?,tags?,plan_page?,blocks_on?,on_page?). A única maneira de criar tarefas —write_noterejeita conteúdo que começa com um marcador de tarefa. - set_task_status — muda apenas o marcador de uma tarefa (
uuid,status); controlado por[tasks].allow_status_change.
Registro de trabalho (diário de hoje; [worklog].enabled)
Um agente que faz trabalho deve poder dizer isso onde o restante do trabalho é registrado — o diário — na mesma forma que um humano mantém manualmente:
#_worklog
#_work/dynamo
((6a9eb940-758e-4966-a31d-f91e79c35f42))
17:50 #_agents/claude/work-scout told how to update
- list_work_projects — o conjunto fechado de projetos sob os quais uma nota pode ser arquivada
(os filhos diretos de
[worklog].namespace, menosexclude). - list_agents — o conjunto fechado de nomes com os quais uma nota pode ser assinada, como
<runtime>/<name>: as páginas exatamente dois níveis abaixo do registro de agentes[worklog].agent_namespace(padrão_agents), de qualquer tempo de execução — um novo (_agents/codex/...) não precisa de configuração. - add_journal_note — acrescenta
HH:MM #<agent> <text>ao diário de hoje sob um projeto (text,work,agent,task?), aninhado sob um((ref))quando uma tarefa é fornecida. - get_worklog_setup_template — a seção de registro de trabalho para o arquivo de instruções de um agente
(CLAUDE.md, AGENTS.md): qual tarefa registrar, quando mudar seu status,
como é uma entrada. Chamado apenas quando o usuário pede para configurar isso — "adicione
o registro de trabalho ao CLAUDE.md" em qualquer sessão é suficiente. O modelo é
worklog_setup.md.
A assinatura fica inline na nota, não como um nível de agrupamento: vários agentes
registrando contra um projeto a dividiriam em subárvores paralelas, cada uma
com sua própria cronologia. Observe que o servidor não pode autenticar o chamador — toda
sessão apresenta o mesmo token de portador — então agent é uma convenção de honestidade
validada contra uma lista, não uma identidade. Ela detecta um erro de digitação, não uma farsa.
O que a lista PODE garantir é que agentes não podem se adicionar a ela. Duas regras sustentam essa linha. O registro vive fora do prefixo de escrita dos agentes, então write_note não pode criar uma página lá — o servidor se recusa a iniciar se estiver configurado dentro. E apenas páginas que têm um arquivo contam: escrever [[_agents/claude/x]] em qualquer nota faz o Logseq criar uma página apenas de referência, o que de outra forma seria suficiente para registrar um nome. Registrar um agente, portanto, significa criar sua página, manualmente, no Logseq.
Cada cabeçalho é reutilizado apenas enquanto ainda for o último bloco no seu nível: o root_block entre os blocos de nível superior do diário, um grupo de projeto dentro da raiz, uma âncora de tarefa dentro do seu grupo. Um diário é cronológico, e um cabeçalho reutilizado onde quer que esteja continua coletando notas posteriores: uma raiz aberta pela manhã renderizaria uma nota da noite acima das linhas da tarde que a precederam, e com dois agentes em dois projetos uma nota se juntaria ao grupo anterior do seu projeto, acima da linha posterior do outro projeto. Assim que qualquer outra coisa cair após um cabeçalho, a próxima nota abre um novo — então o dia é lido na ordem em que as coisas aconteceram, ao custo de cabeçalhos repetidos quando o trabalho se intercala.
Este é o único canal que escreve fora de agent_write_prefix, então ele troca o confinamento de caminho por um contrato estreito: somente anexação, somente diário de hoje, tudo o que ele cria vive sob um root_block, work deve vir do enum, task deve ser um bloco de tarefa existente, e o servidor carimba a hora (um chamador não pode passar uma, então um agente retomado não pode registrar um relógio lembrado). Texto começando com um marcador de tarefa é rejeitado — use create_task.
Dinâmico
- query_<name> — cada consulta de configuração com
register_as_tool = trueé exposta como sua própria ferramenta.
Desenvolvimento
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
Inspecione com o MCP Inspector:
npx @modelcontextprotocol/inspector uv --directory . run mcp-server-logseq
Licença
MIT