Skip to main content
Glama
Logseq MCP Server

Logseq MCP Server

by dailydaniel

Logseq MCP Server

Turn your Logseq graph into memory and workspace for AI agents. A Model Context Protocol server for Logseq with safety-scoped writes, an audit trail in your daily journal, and verified queries exposed as tools. Built on FastMCP (the high-level API of the official mcp package).

PyPI Python 3.11+ License: MIT

Targets the file/Markdown ("OG") version of Logseq — and plain-text files are part of why a graph makes good agent memory: git-syncable, greppable, durable, no lock-in. The newer DB (SQLite) version changed the underlying schema; some methods may behave differently there.

Why

Agents need durable memory, and you already maintain one — your graph. The missing piece is access you can trust: an agent should read broadly and write usefully, but never touch what it shouldn't — and never do anything you can't see. Three design choices make that possible:

  • Namespace-scoped writes. Agents write only under their own prefix (byAgent/ by default), plus one deliberately narrow cross-namespace channel that can change nothing but a task's TODO/DOING/DONE marker. Blacklisted pages are hidden and redacted from every read.

  • An audit trail in your daily journal. Every successful write appends a line like 22:30 [[byAgent]] wrote [[byAgent/readingList/...]] to today's journal — reviewing your agents' work becomes part of a morning routine you already have.

  • Verified queries as tools. Ship known-good Datalog from config as named tools (query_week_plan, …), so agents don't compose datascript by hand and cheaper models stay reliable.

Related MCP server: Logseq MCP Tools

How I use it

I run a small fleet of Claude Code agents with this server on an always-on Mac mini, against my live personal graph:

  • Nightly research. A link dropped into the reading list from the phone; at night an agent claims it (status:: researching), reads the article — or shallow-clones and reads the repo — writes a structured summary onto the page and flips it to read.

  • Morning brief. At 08:30 a small model assembles a one-page dashboard — what was read overnight, week-plan progress, current NOW/DOING tasks — and sends a single push notification.

  • One journal for everyone. The human's tasks and the agents' audit lines interleave in the same daily note:

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

The pages the researcher writes — properties, summary, relevance — link straight into the rest of the graph:

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

Requirements

  • A running Logseq with the local HTTP API server enabled (Settings → Features → HTTP APIs server, then start it from the 🔌 menu).

  • An authorization token created in the HTTP API server settings.

Usage

Claude Code

Local (stdio), token from the environment:

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

Or point it at a remote instance over Streamable HTTP (how phone and remote sessions reach a headless host — see 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"
      }
    }
  }
}

Configuration

Source

Token

URL

Environment

LOGSEQ_API_TOKEN

LOGSEQ_API_URL (default http://localhost:12315)

CLI flag

--api-key

--url

The token is read from the environment or --api-key; it is never stored in code. A .env file is supported (see .env.example).

Config file (optional)

Behaviour beyond the defaults is set in a TOML file — path from LOGSEQ_MCP_CONFIG (default ~/.config/logseq-mcp/config.toml). Custom queries live in EDN files next to it. The server runs fine with no config file (safe read-mostly defaults); see examples/config.toml for a full annotated example.

Section

Key options

[read]

resolve_depth — how deep to expand ((block refs))

[write]

agent_write_prefix (default byAgent), allow_agents_write_any

[search]

files_path — graph folder; set it to use the ripgrep backend

[blacklist]

pages — pages (and subpages) to hide and redact everywhere

[tasks]

allow_status_change — gate for set_task_status; journal_tags — tag roots add_journal_tasks may add tasks under (e.g. ["_study", "_work"]; empty = off)

[audit_log]

enabled — log writes to today's journal

[worklog]

enabled, namespace, root_block, exclude, agent_namespace, agent_exclude — the worklog channel

[queries.<name>]

a named query: file/inline query, register_as_tool, …

Secrets and the API URL stay in the environment, never in this file.

Transports

By default the server runs over stdio (for Claude Desktop and other local clients). A Streamable HTTP transport is also available for remote/networked use (e.g. a phone client):

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

Env vars: LOGSEQ_MCP_TRANSPORT, LOGSEQ_MCP_HOST, LOGSEQ_MCP_PORT, LOGSEQ_MCP_HTTP_TOKEN (or --http-token).

Authentication

The Streamable HTTP transport requires a bearer token: every request must send Authorization: Bearer <LOGSEQ_MCP_HTTP_TOKEN>, or it gets 401. The server refuses to start in this mode without a token set. Note this is a distinct secret from LOGSEQ_API_TOKEN:

Secret

Direction

LOGSEQ_API_TOKEN

this server → Logseq

LOGSEQ_MCP_HTTP_TOKEN

client (phone) → this server

⚠️ A bearer token over plain HTTP is only safe on an already-encrypted channel. Don't expose the raw port to the open internet. The easy path for a home/headless host is Tailscale: install it on the host and the client, and reach http://<host>.<tailnet>.ts.net:8000/mcp over the encrypted tunnel — no domains, nginx, or certificates. (tailscale serve can add TLS if you want https://.)

Docker

Build once:

docker build -t logseq-mcp .

Quick try (ephemeral — --rm removes the container on stop):

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

Persistent deploy (e.g. a headless Mac mini) — run once; --restart brings it back after reboots:

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 — folder holding your config.toml (+ queries/, rules/); set files_path = "/graph" in it to enable file search. Omit both the mount and LOGSEQ_MCP_CONFIG to run on defaults.

  • -v .../graph:/graph — your Logseq graph folder (read-only), for file search.

  • -e TZ=<zone> — local time for audit-log timestamps (image bundles tzdata; the clock is UTC otherwise).

The container serves Streamable HTTP on port 8000 and talks to a Logseq running on the host. On Docker Desktop (macOS/Windows) the default LOGSEQ_API_URL=http://host.docker.internal:12315 already points at the host; on Linux add --add-host=host.docker.internal:host-gateway (or set LOGSEQ_API_URL to the host IP). Make sure Logseq's HTTP API server is running and listening.

Tools

All read output is normalized to a flat JSON shape and passed through the blacklist. Reads resolve ((block refs)) non-lossily (the resolved block's uuid/status is kept so you can act on it). Results go out as compact JSON, and a block carries only the fields it has: empty ones are left out, and raw_content appears only when it differs from text — on a busy journal that is a third of the indented, fully-keyed form.

Find

  • search — full-text search over block content (query, regex?, limit?, case_sensitive?, exclude_journals?). Uses ripgrep over files_path when set, else a datascript content match.

  • find_tasks — task blocks by markers?, tag?, under_tag? (descendant), page?, priority?, limit?.

  • list_pages — page names under a namespace prefix? (depth? limits levels). Discovers a namespace's child pages, which are separate pages a parent's read_page won't show. Structure only, not block content.

  • custom_query — run a named query from the config (name, inputs?).

  • list_custom_queries — list the configured queries.

  • datascript_query — run a raw Datalog query (query, inputs?, rules?).

Guide

  • get_logseq_guide — returns the authoritative guide for querying/writing this graph (verified Datalog gotchas: lowercase names, prefix descendants, marker and journal-day types, tags vs refs, read/write scoping). A single source of truth co-located with the server, so agents don't re-derive (and mis-derive) behaviour.

Read

  • read_page — a page as a normalized block tree (page, depth?). A date YYYY-MM-DD reads that day's journal, whatever the graph's title format; a page that does not exist is an error rather than an empty tree.

  • read_block — a block and its children (uuid, depth?).

Write (agent namespace only)

  • write_note — create/append/replace a page under agent_write_prefix (subpath, content?, mode?, properties?, blocks?). blocks appends whole block trees ({content, children}, e.g. a flashcard with its answer) in one transaction, read back before success; each top-level block gets a persisted id::, and its uuid is returned.

  • set_page_properties — set/remove page properties (subpath, properties; a null value removes one).

  • edit_block — replace one block's content (uuid, old_content, new_content). Read-before-write is enforced: the edit is rejected unless old_content matches the block's exact current content. Agent namespace only.

  • edit_blocks — many edit_block edits in one call (edits), checked per item: the ones that pass apply and are read back, the rest come back as rejected with the reason. One audit line per batch.

Tasks

  • create_task — create a task block in the agent namespace (title, agent, project?, marker?, priority?, tags?, plan_page?, blocks_on?, on_page?). The only way to create tasks — write_note rejects content that starts with a task marker.

  • set_task_status — change only a task's marker (uuid, status); gated by [tasks].allow_status_change.

  • add_journal_tasks — add TODOs the user approved to their journal, under an existing block (parent, tasks: each a title or {title, priority?, page?} → TODO [#P] [[page]] title). The parent must be on a journal page and under a tag from [tasks].journal_tags (#_study, #_work/…, never …/archive/…) — a category header or a ((ref)) to a bigger task in the weekly plan. Append-only, one transaction, read back; a task already open under the same tag (same text, ignoring case, links and priority) is skipped and reported with its uuid.

Worklog (today's journal; [worklog].enabled)

An agent that does work should be able to say so where the rest of the work is recorded — the journal — in the same shape a human keeps by hand:

#_worklog
  #_work/dynamo
    ((6a9eb940-758e-4966-a31d-f91e79c35f42))
      17:50 #_agents/claude/work-scout told how to update
  • list_work_projects — the closed set of projects a note may be filed under (the direct children of [worklog].namespace, minus exclude).

  • list_agents — the closed set of names a note may be signed with, as <runtime>/<name>: the pages exactly two levels below the agent registry [worklog].agent_namespace (default _agents), from any runtime — a new one (_agents/codex/...) needs no config.

  • add_journal_note — append HH:MM #<agent> <text> to today's journal under a project (text, work, agent, task?), nested under a ((ref)) when a task is given.

  • get_worklog_setup_template — the worklog section for an agent's instructions file (CLAUDE.md, AGENTS.md): which task to log under, when to move its status, what an entry looks like. Called only when the user asks to set that up — "add the worklog to CLAUDE.md" in any session is enough. The template is worklog_setup.md.

The signature sits inline on the note, not as a grouping level: several agents logging against one project would otherwise split it into parallel subtrees, each with its own chronology. Note that the server cannot authenticate the caller — every session presents the same bearer token — so agent is an honesty convention validated against a list, not an identity. It catches a typo, not a masquerade.

What the list CAN promise is that agents cannot add themselves to it. Two rules hold that line. The registry lives outside the agents' write prefix, so write_note cannot create a page there — the server refuses to start if it is configured inside. And only pages that have a file count: writing [[_agents/claude/x]] in any note makes Logseq create a reference-only page, which would otherwise be enough to register a name. Registering an agent therefore means creating its page, by hand, in Logseq.

Every header is reused only while it is still the last block at its level: the root_block among the journal's top-level blocks, a project group inside the root, a task anchor inside its group. A journal is chronological, and a header reused wherever it stands keeps collecting later notes: a root opened in the morning would render an evening note above the afternoon lines that preceded it, and with two agents on two projects a note would join its project's earlier group, above the other project's later line. Once anything else lands after a header, the next note opens a fresh one — so the day reads in the order things happened, at the price of repeated headers when work interleaves.

Like add_journal_tasks, it writes outside agent_write_prefix, so it trades path confinement for a narrow contract: append-only, today's journal only, everything it creates lives under a root_block, work must come from the enum, task must be an existing task block, and the server stamps the time (a caller cannot pass one, so a resumed agent can't log a remembered clock). Text starting with a task marker is rejected — use create_task.

Dynamic

  • query_&lt;name&gt; — each config query with register_as_tool = true is exposed as its own tool.

Development

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

Inspect with the MCP Inspector:

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

License

MIT

Available Tools

10 tools
logseq_create_pageB

Create a new page in Logseq with optional properties. Features: - Journal page creation with date formatting - Custom page properties (tags, status, etc.) - Format selection (Markdown/Org-mode) - Automatic first block creation Perfect for template-based page creation and knowledge management.

Inputs: page_name (required), create_first_block, format, journal, +1 more.

logseq_edit_blockC

Enter editing mode for a specific block

Inputs: src_block (required), pos.

logseq_exit_editing_modeC

Exit current editing mode

Inputs: select_block.

logseq_get_all_pagesC

List all pages in the graph with basic metadata

Inputs: repo.

logseq_get_current_pageB

Retrieves the currently active page or block in the user's workspace

Inputs: no named parameters.

logseq_get_current_page_contentB

Get hierarchical block structure of current page

Inputs: no named parameters.

logseq_get_editing_block_contentB

Get content of currently edited block

Inputs: no named parameters.

logseq_get_pageC

Retrieve detailed information about a specific page including metadata and content

Inputs: src_page (required), include_children.

logseq_get_page_contentC

Get block hierarchy for specific page

Inputs: src_page (required).

logseq_insert_blockA

Insert a new block into Logseq. Can create: - Page-level blocks (use is_page_block=true with page name as parent_block) - Nested blocks under existing blocks - Blocks with custom UUIDs for precise reference Supports before/after positioning and property management.

Inputs: content (required), before, custom_uuid, is_page_block, +1 more.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.3/5.0

    Scored across 10 tools

    Disambiguation3/5

    The tools have clear distinct purposes for core operations like creating pages, editing blocks, and retrieving content, but there is notable overlap between retrieval tools. Specifically, logseq_get_page and logseq_get_page_content both retrieve page details, and logseq_get_current_page_content and logseq_get_editing_block_content focus on current workspace content, which could cause confusion in selection. Descriptions help differentiate, but the boundaries are not perfectly distinct.

    Naming Consistency5/5

    All tool names follow a consistent snake_case pattern with a 'logseq_' prefix, using clear verb_noun combinations such as create_page, edit_block, and get_all_pages. This uniformity makes the tools predictable and easy to parse, with no deviations in style or structure across the set.

    Tool Count5/5

    With 10 tools, the count is well-scoped for a Logseq server, covering essential operations like page creation, editing, and content retrieval. Each tool serves a specific function without redundancy, fitting within the typical 3-15 range for such a domain, and no tools feel unnecessary or missing for basic interactions.

    Completeness4/5

    The tool set provides good coverage for core Logseq workflows, including CRUD-like operations for pages and blocks (create, get, edit, insert). However, there are minor gaps, such as no explicit tools for deleting pages or blocks, updating block content beyond editing mode, or managing properties post-creation, which agents might need to work around using existing tools.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      A Model Context Protocol server that provides AI assistants with structured access to your Logseq knowledge graph, enabling retrieval, searching, analysis, and creation of content within your personal knowledge base.
      70
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      A Model Context Protocol server that enables AI agents to interact with local Logseq knowledge graphs, supporting operations like creating/editing pages and blocks, searching content, and managing journal entries.
      13
      15
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      A Model Context Protocol server that enables AI agents to interact with a local Logseq instance, allowing operations like creating pages, managing blocks, and searching across a knowledge graph.
      13
      1
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI assistants to interact with your local Logseq knowledge base through advanced search, content creation, template management, and knowledge organization with privacy-first, local-only operations.
      23 npm
      7
      MIT