From c75dc6f6c71d1ffca94c9b9df116e257ee9704b9 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Fri, 31 Jul 2026 15:01:20 +0200 Subject: [PATCH] add logseq tool: query/modify Logseq DB graph via built-in MCP server - data/tools/logseq: Python wrapper (same pattern as atlassian_cli) - data/tools/logseq.meta: tool metadata with full prompt - data/scripts/logseq-cli: shell bridge using mcp-to-command + mcp-remote - justfile: install logseq tool + logseq-cli script Commands: listPages, getPage, searchBlocks, listTags, listProperties, upsertNodes Transport: streamable-http to http://127.0.0.1:12315/mcp (Logseq 2 DB built-in) --- data/scripts/logseq-cli | 24 ++++++++++++++++ data/tools/logseq | 61 +++++++++++++++++++++++++++++++++++++++++ data/tools/logseq.meta | 17 ++++++++++++ justfile | 4 ++- 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100755 data/scripts/logseq-cli create mode 100755 data/tools/logseq create mode 100644 data/tools/logseq.meta diff --git a/data/scripts/logseq-cli b/data/scripts/logseq-cli new file mode 100755 index 0000000..a830d0c --- /dev/null +++ b/data/scripts/logseq-cli @@ -0,0 +1,24 @@ +#!/bin/sh +set -e + +for cmd in mcp-to-command mcp-remote; do + command -v "$cmd" >/dev/null 2>&1 || { echo "Error: Missing required command: $cmd" >&2; exit 1; } +done + +LOGSEQ_MCP_URL="${LOGSEQ_MCP_URL:-http://127.0.0.1:12315}" + +have_timeout= +command -v timeout >/dev/null 2>&1 && have_timeout=1 + +if [ -n "$have_timeout" ]; then + exec timeout 30 mcp-to-command mcp-remote "$LOGSEQ_MCP_URL/mcp" --transport http-first -- "$@" || { + if [ $? -eq 124 ]; then + echo "Error: timeout exceeded, may want to retry" >&2 + exit 124 + else + exit $? + fi + } +fi + +exec mcp-to-command mcp-remote "$LOGSEQ_MCP_URL/mcp" --transport http-first -- "$@" diff --git a/data/tools/logseq b/data/tools/logseq new file mode 100755 index 0000000..ccdf7f0 --- /dev/null +++ b/data/tools/logseq @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 + +import json +import os +import subprocess +import sys + +sys.path.insert(0, os.environ.get('OLLIE_TOOLS_PATH', os.path.dirname(os.path.abspath(__file__)))) +from _lib.args import parse_args + +RESERVED_KEYS = {"command"} + + +def to_flags(raw: dict) -> list[str]: + """Convert all non-reserved keys to --key=value flags.""" + flags = [] + + for key, value in raw.items(): + if key in RESERVED_KEYS: + continue + + if isinstance(value, str): + try: + parsed = json.loads(value) + if isinstance(parsed, dict): + for k, v in parsed.items(): + flags.append(f"--{k}={v}") + continue + elif isinstance(parsed, list): + for item in parsed: + flags.append(f"--{key}={item}") + continue + except (json.JSONDecodeError, TypeError): + pass + flags.append(f"--{key}={value}") + elif isinstance(value, list): + for item in value: + flags.append(f"--{key}={item}") + elif isinstance(value, bool): + if value: + flags.append(f"--{key}") + elif isinstance(value, dict): + flags.append(f"--{key}={json.dumps(value)}") + else: + flags.append(f"--{key}={value}") + + return flags + + +args = parse_args() +raw = args.raw() +command = args.require("command") + +cmd = ["logseq-cli", command] + to_flags(raw) +result = subprocess.run(cmd, capture_output=True, text=True) + +if result.stdout: + sys.stdout.write(result.stdout) +if result.stderr: + sys.stderr.write(result.stderr) +sys.exit(result.returncode) diff --git a/data/tools/logseq.meta b/data/tools/logseq.meta new file mode 100644 index 0000000..07f0dd6 --- /dev/null +++ b/data/tools/logseq.meta @@ -0,0 +1,17 @@ +{ + "description": "Query and modify your Logseq knowledge graph via the built-in MCP server.", + "prompt": "## logseq\n\nQuery and modify your Logseq DB graph via the built-in MCP server.\n\n**Args**: `command` (required), plus any tool parameters as top-level keys.\n\n### Available commands\n\n```\nlogseq(command=\"listPages\")\nlogseq(command=\"listPages\", expand=true)\nlogseq(command=\"getPage\", pageName=\"My Page\")\nlogseq(command=\"searchBlocks\", searchTerm=\"keyword\")\nlogseq(command=\"listTags\")\nlogseq(command=\"listTags\", expand=true)\nlogseq(command=\"listProperties\")\nlogseq(command=\"listProperties\", expand=true)\nlogseq(command=\"upsertNodes\", operations=[...], dry-run=true)\n```\n\n### upsertNodes operations format\n\nEach operation is an object with:\n- `operation`: \"add\" or \"edit\"\n- `entityType`: \"block\", \"page\", \"tag\", or \"property\"\n- `id`: UUID string (required for edit), temp string for add (if referenced later)\n- `data`: object with fields to set:\n - `title`: page/tag/property name or block content\n - `page-id`: page UUID (required when adding a block)\n - `tags`: list of tag UUIDs\n\nExample: add a block to a page:\n```\nlogseq(command=\"upsertNodes\", operations=[{\"operation\":\"add\",\"entityType\":\"block\",\"id\":null,\"data\":{\"page-id\":\"\",\"title\":\"New block text\"}}])\n```\n\n- Use `dry-run=true` to validate without committing.\n- Before creating a page/tag/property, check if it exists with `getPage`.\n- Every key except `command` becomes a `--key=value` flag.", + "args": { + "type": "object", + "required": ["command"], + "properties": { + "command": { + "type": "string", + "description": "Logseq MCP tool name (listPages, getPage, searchBlocks, listTags, listProperties, upsertNodes)" + } + }, + "additionalProperties": true + }, + "tier": "hot", + "readOnly": false +} diff --git a/justfile b/justfile index 5473cd1..bc3e624 100644 --- a/justfile +++ b/justfile @@ -165,6 +165,7 @@ install-data: install -m755 data/tools/route {{cfg}}/tools/route install -m755 data/tools/subagent_generate {{cfg}}/tools/subagent_generate install -m755 data/tools/subagent_spawn {{cfg}}/tools/subagent_spawn + install -m755 data/tools/logseq {{cfg}}/tools/logseq install -m755 data/tools/system_logs_dmesg {{cfg}}/tools/system_logs_dmesg install -m755 data/tools/system_logs_journald {{cfg}}/tools/system_logs_journald # Tool metadata (.meta sidecar files) @@ -175,10 +176,11 @@ install-data: install -m755 data/tools/_lib/args.sh {{cfg}}/tools/_lib/args.sh # Help install -m644 doc/help.md {{cfg}}/help.md - # Scripts (ollie-remount, ollie-watchdog) + # Scripts (ollie-remount, ollie-watchdog, logseq-cli) mkdir -p {{bin}} install -m755 data/scripts/ollie-remount {{bin}}/ollie-remount install -m755 data/scripts/ollie-watchdog {{bin}}/ollie-watchdog + install -m755 data/scripts/logseq-cli {{bin}}/logseq-cli install-autostart: @echo === Installing autostart files ===