MCP LogSeq

MCP server for LogSeq

Connect Claude to your LogSeq knowledge base. Read, create, and manage pages β€” with optional semantic vector search and DB-mode graph support.

## ✨ What You Can Do Transform your LogSeq knowledge base into an AI-powered workspace! This MCP server enables Claude to seamlessly interact with your LogSeq graphs. ### 🎯 Real-World Examples **πŸ“Š Intelligent Knowledge Management** ``` "Analyze all my project notes from the past month and create a status summary" "Find pages mentioning 'machine learning' and create a study roadmap" "Search for incomplete tasks across all my pages" ``` **πŸ“ Automated Content Creation** ``` "Create a new page called 'Today's Standup' with my meeting notes" "Add today's progress update to my existing project timeline page" "Create a weekly review page from my recent notes" ``` **πŸ” Smart Research & Analysis** ``` "Compare my notes on React vs Vue and highlight key differences" "Find all references to 'customer feedback' and summarize themes" "Create a knowledge map connecting related topics across pages" ``` **🧠 Semantic Search** *(optional, requires vector setup)* ``` "Find everything I wrote about burnout, even if I didn't use that word" "What notes relate to my thoughts on deep work?" "Search across my Dutch and English notes for ideas about productivity" ``` **🀝 Meeting & Documentation Workflow** ``` "Read my meeting notes and create individual task pages for each action item" "Get my journal entries from this week and create a summary page" "Search for 'Q4 planning' and organize all related content into a new overview page" ``` ### πŸ’‘ Key Benefits - **Zero Context Switching**: Claude works directly with your LogSeq data - **Preserve Your Workflow**: No need to export or copy content manually - **Intelligent Organization**: AI-powered page creation, linking, and search - **Enhanced Productivity**: Automate repetitive knowledge work - **Semantic Vector Search** *(optional)*: Find notes by meaning using local Ollama or hosted OpenAI-compatible embeddings - **DB-mode Support** *(opt-in)*: Read and write class properties on Logseq DB-mode graphs --- ## πŸš€ Quick Start ### Step 1: Enable LogSeq API 1. **Settings** β†’ **Features** β†’ Check "Enable HTTP APIs server" 2. Click the **API button (πŸ”Œ)** in LogSeq β†’ **"Start server"** 3. **Generate API token**: API panel β†’ "Authorization tokens" β†’ Create new ### Step 2: Add to your MCP client (No Installation Required!) #### Claude Code ```bash claude mcp add mcp-logseq \ --env LOGSEQ_API_TOKEN=your_token_here \ --env LOGSEQ_API_URL=http://localhost:12315 \ -- uv run --with mcp-logseq mcp-logseq ``` #### Claude Desktop Add to your config file (`Settings β†’ Developer β†’ Edit Config`): ```json { "mcpServers": { "mcp-logseq": { "command": "uv", "args": ["run", "--with", "mcp-logseq", "mcp-logseq"], "env": { "LOGSEQ_API_TOKEN": "your_token_here", "LOGSEQ_API_URL": "http://localhost:12315" } } } } ``` #### Codex CLI With [uv](https://docs.astral.sh/uv/getting-started/installation/) installed and Logseq's HTTP API running (Step 1), add this to `~/.codex/config.toml`: ```toml [mcp_servers.logseq] command = "uv" args = ["run", "--with", "mcp-logseq", "mcp-logseq"] [mcp_servers.logseq.env] LOGSEQ_API_TOKEN = "YOUR_LOGSEQ_TOKEN" LOGSEQ_API_URL = "http://127.0.0.1:12315" ``` Replace `YOUR_LOGSEQ_TOKEN` with your Logseq token. If Codex cannot find `uv`, run `which uv` in Terminal and use the full path for `command`. Keep your token private. Use the API base address above, **without `/mcp`**. Codex runs this adapter through STDIO; the adapter connects to Logseq's regular HTTP API. Restart Codex, open a new local task, and ask: > Use Logseq to list my journal pages, then read today's journal. Do not change anything. Keep Logseq and its API server running. Codex starts the adapter automaticallyβ€”no tunnel or separate Terminal window is needed. *Tested with a Logseq DB graph for page listing and journal retrieval. This setup is for local Codex tasks, not cloud-hosted ChatGPT Chat.* #### OpenCode Add to `~/.config/opencode/opencode.json`: ```json { "$schema": "https://opencode.ai/config.json", "mcp": { "mcp-logseq": { "type": "local", "command": ["uv", "run", "--with", "mcp-logseq", "mcp-logseq"], "enabled": true, "environment": { "LOGSEQ_API_URL": "http://localhost:12315", "LOGSEQ_API_TOKEN": "your_token_here" } } } } ``` ### Step 3: Start Using! ``` "Please help me organize my LogSeq notes. Show me what pages I have." ``` --- ## πŸ”¬ Vector Search (Optional) Semantic search over your Logseq graph using configurable embeddings β€” find notes by meaning, not just keywords. Searches across all your pages using vector similarity and full-text search combined, with cross-language support. Use [Ollama](https://ollama.com) for fully local embeddings, OpenAI, or another OpenAI-compatible embeddings endpoint. [LanceDB](https://lancedb.com) remains local in every configuration. Hosted providers receive the note text being embedded. β†’ **[Full setup guide: VECTOR_SEARCH.md](VECTOR_SEARCH.md)** --- ## πŸ› οΈ Available Tools The server provides 17 tools with intelligent markdown parsing, plus 3 optional vector search tools: | Tool | Purpose | Example Use | |------|---------|-------------| | **`list_pages`** | Browse your graph; `sort: "updated"` / `updated_since` find recently modified pages | "Which pages did I change this week?" | | **`get_page_content`** | Read page content | "Get my project notes" | | **`create_page`** | Add new pages with structured blocks | "Create a meeting notes page with agenda items" | | **`update_page`** | Modify pages (append/replace modes) | "Update my task list" | | **`delete_page`** | Remove pages | "Delete the old draft page" | | **`delete_block`** | Remove a block by UUID | "Delete this specific block" | | **`update_block`** | Edit block content by UUID | "Update this specific block text" | | **`get_block`** | Read a block by UUID with its properties and children | "Show me this specific block" | | **`search`** | Find content across graph | "Search for 'productivity tips'" | | **`query`** | Execute Logseq DSL queries (raw datalog not supported) | "Find all TODO tasks tagged #project" | | **`find_pages_by_property`** | Search pages by property | "Find all pages with status = active" | | **`get_pages_from_namespace`** | List pages in a namespace | "Show all pages under Customer/" | | **`get_pages_tree_from_namespace`** | Hierarchical namespace view | "Show Projects/ as a tree" | | **`rename_page`** | Rename with reference updates | "Rename 'Old Name' to 'New Name'" | | **`get_page_backlinks`** | Find pages linking to a page | "What links to this page?" | | **`insert_nested_block`** | Insert child/sibling blocks | "Add a child block under this task" | | **`set_block_properties`** | Set DB-mode class properties on a block | "Set the status of this block to active" *(DB-mode only)* | | **`vector_search`** βš—οΈ | Semantic search by meaning | "Find notes about shadow work or Jung" | | **`sync_vector_db`** βš—οΈ | Sync vector DB with graph files | "Update the search index" | | **`vector_db_status`** βš—οΈ | Show vector DB health and staleness | "Is my search index up to date?" | βš—οΈ *Requires vector search setup β€” see [VECTOR_SEARCH.md](VECTOR_SEARCH.md)* ### 🎨 Smart Markdown Parsing (v1.1.0+) The `create_page` and `update_page` tools now automatically convert markdown into Logseq's native block structure: **Markdown Input:** ````markdown --- tags: [project, active] priority: high --- # Project Overview Introduction paragraph here. ## Tasks - Task 1 - Subtask A - Subtask B - Task 2 ## Code Example ```python def hello(): print("Hello Logseq!") ``` ```` **Result:** Creates properly nested blocks with: - βœ… Page properties from YAML frontmatter (`tags`, `priority`) - βœ… Hierarchical sections from headings (`#`, `##`, `###`) - βœ… Nested bullet lists with proper indentation - βœ… Code blocks preserved as single blocks - βœ… Checkbox support (`- [ ]` β†’ TODO, `- [x]` β†’ DONE) **Update Modes:** - **`append`** (default): Add new content after existing blocks - **`replace`**: Clear page and replace with new content ### πŸ” Safe Retries & Large Writes `create_page` fails with a clear error if a page with the same title already exists, instead of letting Logseq silently create numbered duplicates (`Page(1)`, `Page 2`, ...). This makes retries after a timeout safe: if a previous `create_page` call timed out but actually committed, the retry tells you the page exists rather than fragmenting your content across ghost pages. For large writes, prefer this pattern over one giant `create_page` call: 1. Create the page with little or no content (`create_page` with just the title and properties) 2. Append content in smaller chunks with `update_page` (`mode: append`) 3. Read back with `get_page_content` to verify the result If you hit the "already exists" error mid-ingest, use `get_page_content` to see what landed, then continue with `update_page` instead of re-creating. --- ## βš™οΈ Prerequisites ### LogSeq Setup - **LogSeq installed** and running - **HTTP APIs server enabled** (Settings β†’ Features) - **API server started** (πŸ”Œ button β†’ "Start server") - **API token generated** (API panel β†’ Authorization tokens) ### System Requirements - **[uv](https://docs.astral.sh/uv/)** Python package manager - **MCP-compatible client** (Claude Code, Claude Desktop, etc.) --- ## πŸ”§ Configuration ### Environment Variables - **`LOGSEQ_API_TOKEN`** (required): Your LogSeq API token - **`LOGSEQ_API_URL`** (optional): Server URL (default: `http://localhost:12315`) - **`LOGSEQ_VERIFY_SSL`** (optional): Whether to verify the TLS certificate of an `https://` `LOGSEQ_API_URL`. Defaults to verifying when the URL is `https://`; set to `0`, `false`, or `no` to skip verification for self-signed certificates. Any other value enables verification. - **`LOGSEQ_API_CONNECT_TIMEOUT`** (optional): HTTP connect timeout in seconds (default: `3`) - **`LOGSEQ_API_READ_TIMEOUT`** (optional): HTTP read timeout in seconds (default: `6`) - **`LOGSEQ_LOG_LEVEL`** (optional): Log verbosity β€” `DEBUG`, `INFO`, `WARNING`, `ERROR`, or `CRITICAL` (default: `INFO`). Logs go to stderr. At `DEBUG`, the MCP SDK's own logger stays capped at `INFO` so full request payloads are not logged. - **`LOGSEQ_LOG_FILE`** (optional): Path to a log file. When unset (the default), nothing is written to disk. Tool calls are logged with argument names and result sizes only, so page/block content does not appear in routine logs. - **`LOGSEQ_DB_MODE`** (optional): Set to `true` to enable DB-mode property support. Only for Logseq DB-mode graphs (beta). Markdown/file-based graph users should leave this unset. - **`LOGSEQ_EXCLUDE_TAGS`** (optional): Comma-separated tags β€” pages with these tags are hidden from all tools. See [Privacy & Access Control](#-privacy--access-control) below. - **`LOGSEQ_INCLUDE_NAMESPACES`** (optional): Comma-separated namespace allow-list (e.g. `work,projects`). When set, **only** pages in these namespaces and their sub-pages are accessible β€” everything else, including top-level pages without a namespace, is hidden from listings/search and denied on direct access. See [Privacy & Access Control](#-privacy--access-control) below. - **`LOGSEQ_EXCLUDE_NAMESPACES`** (optional): Comma-separated namespace deny-list (e.g. `finance,work/secret`). These namespaces are always blocked, taking priority over the include list. See [Privacy & Access Control](#-privacy--access-control) below. - **`LOGSEQ_WRITE_NAMESPACES`** (optional): Comma-separated write allow-list (e.g. `Beren`). When set, write tools may only target pages in these namespaces; everything else that is readable stays read-only. Applied on top of the include/exclude rules, never instead of them. See [Privacy & Access Control](#-privacy--access-control) below. - **`LOGSEQ_CONFIG_FILE`** (optional): Path to a shared JSON config file holding the graph path, ACL defaults, and the `vector` block. Env vars (`LOGSEQ_EXCLUDE_TAGS`, `LOGSEQ_INCLUDE_NAMESPACES`, `LOGSEQ_EXCLUDE_NAMESPACES`, `LOGSEQ_WRITE_NAMESPACES`) override the matching keys in this file. - **`MCP_HTTP_AUTH_TOKEN`** (required for `--transport http`): Bearer token clients must send as `Authorization: Bearer `. The server refuses to start in HTTP mode without it. See [Serving over HTTP](docs/SERVING.md). ### Privacy & Access Control Pages tagged with excluded tags are completely hidden from AI β€” they won't appear in listings, searches, or queries, and attempting to read them directly returns an access-denied error. **Quick setup via env var:** ```bash LOGSEQ_EXCLUDE_TAGS=private,secret ``` **Via config file** (also used for [vector search](VECTOR_SEARCH.md)): ```json { "logseq_graph_path": "/path/to/your/logseq/pages", "exclude_tags": ["private", "secret"] } ``` Point to it with `LOGSEQ_CONFIG_FILE=/path/to/config.json`. In your Logseq pages, tag any page you want to protect: ``` tags:: private ``` The exclusion applies to all tools: `list_pages`, `get_page_content`, `search`, `query`, and the optional vector search. If you also use vector search, `exclude_tags` at the root is automatically merged into the vector index exclusion list β€” private pages are never embedded. #### Namespace access control You can restrict access to specific namespaces using `LOGSEQ_INCLUDE_NAMESPACES` and `LOGSEQ_EXCLUDE_NAMESPACES`. **Include list (strict allow-list):** Only the listed namespaces and their sub-pages are visible; everything else is hidden. ```bash LOGSEQ_INCLUDE_NAMESPACES=work,projects ``` **Exclude list (deny-list):** The listed namespaces are always blocked, even if they appear in the include list. ```bash LOGSEQ_EXCLUDE_NAMESPACES=work/secret,finance ``` **Via config file:** ```json { "include_namespaces": ["work", "projects"], "exclude_namespaces": ["work/secret", "finance"], "write_namespaces": ["work/drafts"] } ``` **Write list (write allow-list):** Everything the read rules allow stays readable, but write tools (`create_page`, `update_page`, `delete_page`, `rename_page`, `update_block`, `delete_block`, `insert_nested_block`, `set_block_properties`) may only target pages in these namespaces. Useful when an assistant should read a wider area than it may edit: ```bash LOGSEQ_INCLUDE_NAMESPACES=Family,Beren LOGSEQ_WRITE_NAMESPACES=Beren # reads Family/* and Beren/*, writes only Beren/* ``` `rename_page` needs both the old and the new name inside the write list; block tools are checked against the block's owning page (denied if it cannot be resolved). A write outside the list returns "page 'X' is read-only for this assistant". The write list never widens read access: a write namespace not covered by the include list is still denied (a warning is logged at startup). Unset means no extra restriction. Every allowed write is logged at INFO as `Write: tool= page=` (names only, never content). Matching is segment-based and case-insensitive: `work` matches `work` and `work/projects` but not `workshop`. The behavior mirrors `LOGSEQ_EXCLUDE_TAGS`: list/search results silently omit blocked pages; direct read, write, delete, and block operations return an access-denied error. Access control is enforced at the **page** level and applied across every tool: list/search/query results omit blocked pages, direct page/block access and backlinks are denied, and vector search is filtered. Block-level results from `search` and `query` are resolved back to their owning page, so a block belonging to a restricted page is filtered out of those results too. **Index-time namespace scoping (vector DB only).** The keys above are *query-time*: every page is embedded, and blocked ones are filtered out of each response. For the vector DB you can also scope at *index time* β€” decide which namespaces are embedded into the DB **at all** β€” with `include_namespaces` / `exclude_namespaces` inside the `vector` block of the config file: ```json { "vector": { "enabled": true, "include_namespaces": ["work"], "exclude_namespaces": ["work/secret"] } } ``` This is global (it shapes the shared DB for every consumer), and it keeps unwanted content off disk entirely rather than filtering it on read β€” useful for secrets you never want embedded, or to keep the index small when everyone only cares about a subset. Matching is the same segment-based, case-insensitive rule. Because it changes what the index contains, it only takes effect after a full re-index: `logseq-sync --rebuild`. ### 🌐 Serving over HTTP, multi-profile & TLS By default the server speaks **stdio** β€” your client spawns it as a subprocess, and most users need nothing more. To serve **sandboxed or remote clients** over the network, `mcp-logseq` can run as a long-lived HTTP service with bearer auth, per-profile isolation, and TLS: ```bash mcp-logseq --transport http --host 127.0.0.1 --port 12320 # requires MCP_HTTP_AUTH_TOKEN ``` The full deployment guide β€” the server-side **security model**, the **per-profile multi-instance** pattern, the separate **`logseq-sync` writer**, and native **TLS** / reverse-proxy setup β€” lives in **[docs/SERVING.md](docs/SERVING.md)**. Non-loopback binds over plain HTTP are refused unless you supply TLS or pass `--insecure`. ### Alternative Setup Methods #### Using .env file ```bash # .env LOGSEQ_API_TOKEN=your_token_here LOGSEQ_API_URL=http://localhost:12315 ``` #### System environment variables ```bash export LOGSEQ_API_TOKEN=your_token_here export LOGSEQ_API_URL=http://localhost:12315 ``` --- ## πŸ” Verification & Testing ### Test LogSeq Connection ```bash uv run --with mcp-logseq python -c " from mcp_logseq.logseq import LogSeq api = LogSeq(api_key='your_token') print(f'Connected! Found {len(api.list_pages())} pages') " ``` ### Verify MCP Registration ```bash claude mcp list # Should show mcp-logseq ``` ### Debug with MCP Inspector ```bash npx @modelcontextprotocol/inspector uv run --with mcp-logseq mcp-logseq ``` --- ## πŸ› Troubleshooting ### Common Issues #### "LOGSEQ_API_TOKEN environment variable required" - βœ… Enable HTTP APIs in **Settings β†’ Features** - βœ… Click **πŸ”Œ button** β†’ **"Start server"** in LogSeq - βœ… Generate token in **API panel β†’ Authorization tokens** - βœ… Verify token in your configuration #### "spawn uv ENOENT" (Claude Desktop) Claude Desktop can't find `uv`. Use the full path: ```bash which uv # Find your uv location ``` Update config with full path: ```json { "mcpServers": { "mcp-logseq": { "command": "/Users/username/.local/bin/uv", "args": ["run", "--with", "mcp-logseq", "mcp-logseq"], "env": { "LOGSEQ_API_TOKEN": "your_token_here" } } } } ``` **Common uv locations:** - Curl install: `~/.local/bin/uv` - Homebrew: `/opt/homebrew/bin/uv` - Pip install: Check with `which uv` #### Connection Issues - βœ… Confirm LogSeq is running - βœ… Verify API server is **started** (not just enabled) - βœ… Check port 12315 is accessible - βœ… Test with verification command above --- ## πŸ‘©β€πŸ’» Development For local development, testing, and contributing, see **[DEVELOPMENT.md](DEVELOPMENT.md)**. ---

Ready to supercharge your LogSeq workflow with AI?

⭐ Star this repo if you find it helpful!