Logseq AI
Provides comprehensive tools for interacting with Logseq graphs, enabling AI agents to search for and manage pages and blocks, execute Datalog queries, track tasks and deadlines, and manage journal entries through the Logseq HTTP API.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Logseq AIList all my overdue tasks"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Logseq AI
AI-powered interactions with Logseq through two interfaces:
MCP Server - Enables external AI tools (Windsurf, Claude Desktop) to interact with your Logseq graph
Lain - Embedded AI assistant plugin within the Logseq UI
"No matter where you go, everyone's connected." - Serial Experiments Lain
Prerequisites
Node.js 18+
Logseq 2.x with a DB graph. File graphs (Logseq 1.x) are not supported — they use the older
:block/content/:block/markerschema. The tools detect the graph type and fail with a clear message rather than returning empty results.HTTP API server enabled (Settings → Features → HTTP APIs server)
Keep the Logseq window visible while the MCP server is in use. When the window is minimized or on another virtual desktop, Chromium throttles the timers Logseq's request queue depends on, and write calls hang until it regains focus. See doc/logseq-api-notes.md.
Task model in 2.x
Logseq 2.x replaced text markers with properties, so the task tools use Logseq's native vocabulary:
Values | |
Status |
|
Priority |
|
Legacy spellings are still accepted on input and normalized (TODO → Todo,
A → High), so existing prompts keep working. Writing "TODO buy milk" as
block text, however, no longer creates a task — use create_task.
Related MCP server: Logseq MCP Server
Setup
# Install dependencies
pnpm install
# Build all packages
pnpm buildWith just installed, just install and
just build do the same; see Development for the full list.
Quick Start
Using the Core Library
import { LogseqClient, LogseqOperations } from "@logseq-ai/core";
// Create client and operations
const client = new LogseqClient({
baseUrl: "http://localhost:12315",
token: "your-api-token" // optional
});
const ops = new LogseqOperations(client);
// Search for pages
const results = await ops.search("meeting notes");
// Get page content as text
const content = await ops.getPageContent("My Notes");
// Create a new block
const block = await ops.createBlock({
pageName: "My Notes",
content: "New idea from AI!"
});
// Create multiple blocks with hierarchy (more efficient for structured content)
const result = await ops.createBlocks("My Notes", [
{
content: "## Project Overview",
children: [
{ content: "Goal: Build a new feature" },
{ content: "Timeline: Q1 2025" },
]
},
{
content: "## Tasks",
children: [
{ content: "Design the API" },
{ content: "Implement backend" },
{ content: "Write tests" },
]
}
]);
console.log(`Created ${result.created} blocks`);
// Run a Datalog query to find tasks.
// DB graphs store block text in :block/title; :block/content and
// :block/marker no longer exist.
const tasks = await ops.query(`
[:find (pull ?b [:block/uuid :block/title])
:where
[?b :block/tags ?t]
[?t :db/ident :logseq.class/Task]]
`);Task Management
import { LogseqClient, LogseqOperations } from "@logseq-ai/core";
const client = new LogseqClient();
const ops = new LogseqOperations(client);
// Get open tasks (Backlog, Todo, Doing, In Review)
const tasks = await ops.getTasks();
// Or filter to specific statuses
const inFlight = await ops.getTasks({ statuses: ["Doing", "In Review"] });
// Get tasks from a specific page
const projectTasks = await ops.getTasks({ pageName: "Project A" });
// Create a task. In a DB graph this is a block tagged with Logseq's Task
// class - do NOT prefix the content with "TODO", that is just literal text.
const task = await ops.createTask({
pageName: "Project A",
content: "Review pull request",
priority: "High", // Low | Medium | High | Urgent
deadline: "2026-08-15"
});
// Move it through the workflow
await ops.markTask(task.uuid, "Doing");
await ops.markTask(task.uuid, "In Review");
await ops.markTask(task.uuid, "Done");
// Set/change priority
await ops.setTaskPriority(task.uuid, "Medium");
// Set scheduled date
await ops.setTaskScheduled({ uuid: task.uuid, date: "2026-08-10" });
// Remove deadline
await ops.setTaskDeadline({ uuid: task.uuid, date: null });Task Analytics
// Get overdue tasks
const overdue = await ops.getOverdueTasks();
console.log(`You have ${overdue.length} overdue tasks`);
// Get tasks due in the next 7 days
const dueSoon = await ops.getTasksDueSoon({ days: 7 });
// Get task statistics
const stats = await ops.getTaskStats();
console.log(`Total: ${stats.total}, Overdue: ${stats.overdue}`);
console.log(`By status:`, stats.byStatus);
// Search tasks by keyword
const reviewTasks = await ops.searchTasks({ query: "review", statuses: ["Todo"] });Journal Operations
// Get or create today's journal
const today = await ops.getToday();
console.log(`Today's journal: ${today.page.title}`);
// Quick capture to today's journal
await ops.appendToToday("Meeting notes: discussed Q1 roadmap");
// Get recent journal entries
const journals = await ops.getRecentJournals({ days: 7, includeContent: true });
journals.forEach(j => console.log(`${j.date}: ${j.content.substring(0, 50)}...`));Page Links & Backlinks
// Find pages related to a topic
const links = await ops.findRelatedPages("Project A");
console.log("Pages linking to Project A:", links.backlinks);
console.log("Pages Project A links to:", links.forwardLinks);
// Find blocks referencing a specific block
const backlinks = await ops.getBlockBacklinks("block-uuid-123");
console.log(`Found ${backlinks.backlinks.length} references`);Error Handling
import {
LogseqOperations,
LogseqApiError,
LogseqNotFoundError,
isLogseqError
} from "@logseq-ai/core";
try {
await ops.getPageContent("Nonexistent Page");
} catch (error) {
if (error instanceof LogseqNotFoundError) {
console.log(`Page not found: ${error.identifier}`);
} else if (isLogseqError(error)) {
console.log(`Logseq error: ${error.toDetailedString()}`);
}
}Packages
@logseq-ai/core
Shared library for Logseq API interactions. Used by both the MCP server and plugin.
Key exports:
LogseqClient- Low-level HTTP client for Logseq APILogseqOperations- High-level operations with error handlingError classes:
LogseqError,LogseqApiError,LogseqConnectionError,LogseqNotFoundError,LogseqValidationErrorType definitions:
Page,Block,SearchResult, etc.
@logseq-ai/mcp-server
MCP server that exposes Logseq operations as tools for AI clients.
Features:
43 tools for comprehensive Logseq interaction
Input validation with clear error messages (powered by Zod)
Proper error handling for Logseq API errors
# Build
pnpm --filter @logseq-ai/mcp-server build
# Run
LOGSEQ_API_TOKEN=your-token pnpm --filter @logseq-ai/mcp-server start
# Test
pnpm --filter @logseq-ai/mcp-server testConfigure in Windsurf/Claude Desktop
Add to your MCP configuration:
{
"mcpServers": {
"logseq": {
"command": "node",
"args": ["/path/to/logseq-ai/packages/mcp-server/dist/index.js"],
"env": {
"LOGSEQ_API_URL": "http://localhost:12315",
"LOGSEQ_API_TOKEN": "your-token"
}
}
}
}Variable | Default | Description |
|
| Base URL of the Logseq HTTP API server |
| (none) | Authorization token |
|
| Retries for transient failures; |
The client retries transient failures with exponential backoff and jitter. Connection failures are retried for any call, since the request never reached Logseq. Timeouts — including the empty response Logseq returns when its window is backgrounded — are retried for reads only: a mutation may have been applied before the response was lost, so replaying it could duplicate a block or page. Logseq handler errors are never retried.
A write that times out is reported as uncertain, not failed. Logseq cannot cancel a handler that is already running, so a timed-out write can commit seconds or minutes later — retrying it blindly is how one appended block becomes two. Where a cheap read-back exists, the error says what is actually there ("a page titled X now exists…", "2 blocks with this exact text are already on Y…"). A tree write that fails partway names the blocks that already landed, so the fix is to repair the page rather than write it again.
Available Tools
Page & Block Operations
Tool | Description |
| Search for pages and blocks |
| Get page content as plain text ( |
| Get one block and its children by uuid, with uuids attached |
| Find blocks by text, page, and/or tag - structured, escaped, bin-filtered |
| Get multiple pages in a batch (more efficient) |
| Get page with backlinks and forward links |
| List all pages in the graph |
| Create a new page (optionally with blocks) |
| Delete a page (moves it to the recycle bin) |
| Rename a page; references follow automatically |
| List pages in the recycle bin |
| Restore a page from the recycle bin |
| Create a single block |
| Create multiple blocks with hierarchy, on a page or under a block |
| Update a block's content |
| Delete a block |
| Run Datalog queries |
| Update properties on an existing page |
Graph Discovery
Tool | Description |
| Get current graph info |
| Get graph statistics (pages by type, orphans, etc.) |
| Find referenced pages that don't exist |
| Find pages with no incoming links |
| Find pages by property values |
| Find backlinks and forward links |
| Find blocks referencing a block |
Journal Operations
Tool | Description |
| Get today's journal page |
| Add content to today's journal |
| Get recent journal entries |
Task Management
Tool | Description |
| Get open tasks (Backlog/Todo/Doing/In Review) |
| Create a new task |
| Change task status |
| Change multiple tasks' status (batch) |
| Search tasks by keyword |
| Get tasks past deadline |
| Get tasks due within N days |
| Get task statistics |
| Set task priority (Low/Medium/High/Urgent) |
| Set task deadline |
| Set task scheduled date |
Example: Creating Structured Content
When creating pages with multiple sections, use create_blocks for efficiency:
User: Create a page about Python with sections for Overview, Features, and Links
AI uses:
1. create_page({ pageName: "Python", tags: ["Technology"], properties: { Topic: "Programming" } })
2. create_blocks({
pageName: "Python",
blocks: [
{
content: "## Overview",
children: [
{ content: "Python is a high-level programming language." }
]
},
{
content: "## Features",
children: [
{ content: "Dynamic typing" },
{ content: "Garbage collection" }
]
},
{
content: "## Links",
children: [
{ content: "[Official Site](https://python.org)" }
]
}
]
})To extend a section later, pass parentBlockUuid instead of pageName — the
tree lands under that block rather than at the top level of the page. Both
create_block and create_blocks take exactly one of the two; passing both is
an error rather than a silently ignored argument:
create_blocks({
parentBlockUuid: "<uuid of the '## Features' block>",
blocks: [{ content: "Large standard library" }]
})Block Content Rules
Every tool that writes block text (create_block, create_blocks,
create_page, update_block, append_to_today, create_task, and template
variable values) validates it first. Logseq accepts unsupported markup and
stores it verbatim, so these mistakes succeed silently and corrupt the graph
quietly; the MCP server rejects them with a message naming the fix instead:
One logical unit per block. No markdown list markers (
-,1.), no second heading, no heading mixed with body text — Logseq is an outliner and renders one bullet per block. Usechildrenfor structure.No file-graph task markup. A
TODOprefix makes an ordinary block, not a task;[#A]creates a tag literally namedA]. Usecreate_task,mark_taskandset_task_priority.No
key:: valuetext. DB graphs store properties as structured fields — use thepropertiesargument orupdate_page_properties.No
[[Page|label]](a Roam convention) and no unbalanced[[. Write[[Page]], or[label]([[Page]])for different link text.
Fenced code blocks are exempt — inside them the markup is meant literally. Multi-line prose is fine; only list and heading structure has to be split across blocks.
Page References
Write references as [[Page Title]]. A DB graph stores them by uuid, so before
writing, each title is resolved to a page — created once if it does not exist
yet — and rewritten to [[uuid]]. Letting Logseq auto-create reference targets
per insert is what produced duplicate pages for the same title.
Resolving up front also lets a whole block tree go in as a single request, so a timeout cannot leave a half-built page behind. If a title cannot be resolved, that tree falls back to one insert per block, which resolves references itself at the cost of atomicity.
Reads go the other way: get_page and friends render [[uuid]] back as
[[Page Title]], resolving every reference on the page in one query. A uuid
whose page cannot be named is left as-is rather than dropped.
Editing What You Read
Every edit tool addresses blocks by uuid, so reads can hand you the uuids
directly: pass includeUuids: true to get_page and each line comes back as
- text ((uuid)), ready for update_block, delete_block, or
create_blocks({ parentBlockUuid }). get_block re-reads a single subtree by
uuid (uuids always included), and find_blocks locates blocks by text, page,
and/or tag without hand-writing Datalog - values are escaped and recycle-bin
content filtered automatically.
The Recycle Bin
delete_page never erases: Logseq stamps the page deleted-at and hides it,
and the title cannot be reused while the page sits in the bin. list_deleted_pages
shows what is in there, restore_page brings a page back (verified by re-reading,
since Logseq reports success even for property writes it discards), and
rename_page frees a title without deleting anything. Rename and restore both
refuse conflicting titles - live or recycled - rather than creating duplicates.
logseq-lain
Lain - AI assistant plugin for Logseq.
# Build
pnpm --filter logseq-lain build
# Development (watch mode)
pnpm dev:pluginInstall in Logseq
Enable Developer Mode in Logseq (Settings → Advanced → Developer mode)
Go to Plugins → Load unpacked plugin
Select the
packages/logseq-plugindirectoryUse
/lain ask,/lain summarize,/lain expandslash commands
Architecture
See doc/architecture.md for detailed architecture documentation.
Development
Common tasks are wrapped in a justfile. Run just to see them all.
just check # format-check, lint, typecheck, test — everything CI enforces
just test # run all test suites (489 tests)
just typecheck # tsc across all three packages
just lint # eslint
just format-check # prettier, without writing
just coverage # tests with a coverage report
just fix # apply formatting and fixable lint rules, then re-check
just build # compile every packageEach recipe is a thin wrapper over the equivalent pnpm script, so
pnpm test, pnpm typecheck and friends still work on their own.
just check orders its steps cheapest-failure-first, so a formatting slip
surfaces before the test suite runs.
Test layout
Package | Tests | Covers |
| 256 | Client transport, DB idents, operations, tasks, templates, errors |
| 233 | Tool registry wiring, Zod validation, handler dispatch and output |
The mcp-server tests run against a stubbed LogseqOperations, so they need
no running Logseq. The tool-registry tests assert that every advertised tool
resolves to a handler — a tool without one is otherwise invisible until a
client calls it and gets Unknown tool.
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityAmaintenanceInteracts with LogSeq via its API.Last updated17316MIT
- Alicense-qualityDmaintenanceEnables 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.Last updated487MIT
- AlicenseBqualityBmaintenanceEnables AI assistants like Claude to directly read, write, search, and navigate your local Logseq knowledge graph, including managing journals, pages, backlinks, and page relationships without manual copy-pasting.Last updated11285MIT
- Alicense-qualityDmaintenanceConnects AI assistants to Logseq knowledge graphs to read, write, and search pages, blocks, and journals via the Model Context Protocol. It features 17 tools for full graph management, including CRUD operations, batch block insertion, and full-text search.Last updated48Apache 2.0
Related MCP Connectors
Persistent memory and knowledge management for AI agents with semantic search and 50+ tools.
Gateway between LLM agents and world data through eight tools and a bundled endpoint catalog.
Connect AI assistants to your GitHub-hosted Obsidian vault to seamlessly access, search, and analy…
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/HarrisonTotty/logseq-ai'
If you have feedback or need assistance with the MCP directory API, please join our Discord server