A simple HTTP server that provides REST API access to Logseq CLI commands. Enables browser extensions and other applications to query Logseq DB graphs without requiring the Logseq Desktop app to be running.
- ✅ Works independently - Logseq Desktop does NOT need to be running
- ✅ DB Graphs only - Works with Logseq database graphs
- ✅ Full-text search - Search across all block content, not just titles
- ✅ Simple setup - Just run one command
- ✅ Browser agnostic - Works with any browser
- ✅ Easy to debug - Test with curl or browser
- ✅ CORS enabled - Works with browser extensions
- ✅ Privacy-safe logging - Search queries not logged by default
- ✅ macOS background service - Auto-start on login with GUI control app
Current: v0.0.4 - See VERSION.md for changelog
This version requires @logseq/cli v4.0 or higher.
If you're upgrading from v0.0.3 or earlier:
# Update the CLI
npm update -g @logseq/cli
# Verify version (should be 0.4.0 or higher)
logseq --versionThe CLI v4.0 changed how graph arguments are passed. This server has been updated to use the new -g flag format.
-
Python 3 (macOS ships with Python 3)
python3 --version
-
Logseq CLI v4.0+
⚠️ Version 4.0 or higher requirednpm install -g @logseq/cli # or yarn global add @logseq/cliVerify (must show 0.4.0 or higher):
logseq --version
-
jet (EDN to JSON converter)
brew install borkdude/brew/jet
Verify:
jet --version
-
Logseq DB graphs - The CLI only works with Logseq DB (database) graphs, not file-based/markdown graphs.
cd /Users/niyaro/Documents/Code/logseq-http-server
python3 logseq_server.pyThe server will start on http://localhost:8765
Open a browser and visit:
- Health check: http://localhost:8765/health
- List graphs: http://localhost:8765/list
Or use curl:
curl http://localhost:8765/list- Go to
chrome://extensions/ - Enable "Developer mode"
- Click "Load unpacked"
- Select
/Users/niyaro/Documents/Code/logseq-http-server/example-extension - Click the extension icon - it should connect automatically!
http://localhost:8765
GET /health
Check if server is running.
Response:
{
"status": "healthy",
"message": "Logseq HTTP Server is running"
}GET /list
List all available Logseq DB graphs.
Response:
{
"success": true,
"stdout": "DB Graphs:\n research-notes\n personal\n",
"stderr": "",
"returncode": 0
}GET /show?graph=GRAPH_NAME
Show information about a specific graph.
Parameters:
graph(required) - Graph name
Example:
curl "http://localhost:8765/show?graph=research-notes"GET /search?q=QUERY[&graph=GRAPH_NAME]
Search across graphs or in a specific graph. Performs full-text search across all block content.
Parameters:
q(required) - Search querygraph(optional) - Limit search to specific graph
Example:
curl "http://localhost:8765/search?q=anthropology"
curl "http://localhost:8765/search?q=anthropology&graph=research-notes"Response:
{
"success": true,
"data": [
{
"block/uuid": "...",
"block/title": "...",
"block/page": {...}
}
],
"returncode": 0
}POST /query
Content-Type: application/json
{
"graph": "GRAPH_NAME",
"query": "DATALOG_QUERY"
}
Execute a datalog query on a graph.
Body:
{
"graph": "research-notes",
"query": "[:find (pull ?b [:block/uuid :block/title :block/page]) :where [?b :block/title ?t] [(clojure.string/includes? ?t \"keyword\")]]"
}Example:
curl -X POST http://localhost:8765/query \
-H "Content-Type: application/json" \
-d '{"graph":"research-notes","query":"[:find (pull ?b [*]) :where [?b :block/content]]"}'All endpoints return JSON with this structure:
{
"success": true|false,
"stdout": "command output",
"stderr": "error output if any",
"returncode": 0,
"data": {} // Parsed JSON if stdout is JSON
}{
"manifest_version": 3,
"permissions": ["storage"],
"host_permissions": ["http://localhost:8765/*"]
}// List graphs
const response = await fetch('http://localhost:8765/list');
const data = await response.json();
console.log(data.stdout);
// Search
const searchResponse = await fetch(
'http://localhost:8765/search?q=keyword'
);
const searchData = await searchResponse.json();
// Execute query
const queryResponse = await fetch('http://localhost:8765/query', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
graph: 'my-graph',
query: '[:find (pull ?b [:block/uuid :block/title]) :where [?b :block/title]]'
})
});python3 logseq_server.py [--port PORT] [--host HOST] [--debug]Options:
--port- Port to listen on (default: 8765)--host- Host to bind to (default: localhost)--debug- Enable debug logging (logs all queries - privacy warning!)
Examples:
# Use a different port
python3 logseq_server.py --port 9000
# Allow connections from other machines (be careful!)
python3 logseq_server.py --host 0.0.0.0
# Enable debug mode for troubleshooting
python3 logseq_server.py --debugBy default, the server uses privacy-safe logging:
- ✅ Logs server startup/shutdown and errors
- ✅ Logs health check requests
- ❌ Does NOT log search queries, graph names, or URLs
Log location:
- File:
/tmp/logseq-server.log(for LaunchAgent) orlogseq-http-server.log(manual run) - Console: stdout
View logs in real-time:
tail -f /tmp/logseq-server.logFor troubleshooting, enable debug mode to log all requests:
python3 logseq_server.py --debug- Disable debug mode after troubleshooting
- Clear logs:
cat /dev/null > /tmp/logseq-server.log
See macos/README.md for instructions on enabling debug mode with the LaunchAgent.
By default, the server allows requests from any origin (Access-Control-Allow-Origin: *). This is fine for local development.
For production, edit logseq_server.py and restrict CORS:
# In _set_headers method, change:
self.send_header('Access-Control-Allow-Origin', '*')
# To:
self.send_header('Access-Control-Allow-Origin', 'chrome-extension://YOUR_EXTENSION_ID')By default, the server only listens on localhost, making it inaccessible from other machines. Keep it this way unless you specifically need remote access.
The server only executes safe Logseq CLI commands (list, show, search, query, export). No arbitrary shell execution is possible.
Install the Logseq CLI:
npm install -g @logseq/cliVerify installation:
which logseq
logseq --versionInstall jet:
brew install borkdude/brew/jetVerify installation:
which jet
jet --versionMake sure the server is running:
python3 logseq_server.pyCheck the logs:
tail -f logseq-http-server.logThe CLI only works with Logseq DB graphs.
Verify graphs are accessible:
logseq listUse a different port:
python3 logseq_server.py --port 9000Then update your extension to use the new port.
Use the automated installer and GUI control app!
See macos/README.md for:
- 🚀 One-command installation
- 📱 GUI control app
- 🔄 Auto-start on login
- 🐛 Debug mode toggle
- 📝 Log viewing/clearing
Quick install:
cd /Users/niyaro/Documents/Code/logseq-http-server/macos
./install.shThen use /Applications/Logseq Server Control.app to manage the server.
Using nohup:
nohup python3 logseq_server.py > /dev/null 2>&1 &Stop it:
pkill -f logseq_server.pyTo use this server with the Logseq DB Sidekick extension:
-
Start the HTTP server (see Quick Start above)
-
Install and configure the extension:
- Set server URL to
http://localhost:8765 - Select your graph from the dropdown
- Click "Connect" to verify connection
- Set server URL to
-
Browse the web - relevant notes will appear when you search!
- Extension sends HTTP request to server
- Server executes
logseqCLI command - CLI returns results in EDN format (Clojure data notation)
- Server pipes output through
jetto convert EDN → JSON - Server returns JSON to extension
- Extension displays results in browser
- @logseq/cli - Official Logseq command-line interface
- jet - EDN to JSON converter (https://github.com/borkdude/jet)
- Python 3 - Standard library only, no pip packages needed
MIT
Contributions welcome! This is a simple tool - feel free to fork and improve.