Skip to main content
Glama
logseq_client.py8.22 kB
import requests import os from typing import Dict, List, Optional, Any, Union class LogseqAPIClient: """Client for interacting with the Logseq API""" def __init__(self, api_url: str = None, token: str = None): """ Initialize the Logseq API client Args: api_url: URL of the Logseq API (default from mcp config) token: API token for authentication (default from mcp config) """ self.api_url = api_url or os.getenv("LOGSEQ_API_URL", "http://localhost:12315") self.token = token or os.getenv("LOGSEQ_TOKEN") def _get_headers(self) -> Dict[str, str]: """Get headers for API requests""" headers = { "Content-Type": "application/json" } if self.token: headers["Authorization"] = f"Bearer {self.token}" return headers def call_api(self, method: str, args: List = None) -> Any: """ Call the Logseq API using the proper format Args: method: API method to call (e.g., "logseq.Editor.getCurrentBlock") args: Arguments for the method Returns: API response (could be a dict, list, or other JSON-serializable data) """ url = f"{self.api_url}/api" headers = self._get_headers() data = { "method": method, "args": args or [] } try: response = requests.post(url, headers=headers, json=data) if response.status_code == 401: return { "success": False, "error": f"401 Unauthorized: Please provide a valid token in LOGSEQ_API_TOKEN environment variable" } response.raise_for_status() # Parse JSON response json_response = response.json() # Some Logseq API endpoints return the result directly, others wrap it in a result field # We need to handle both cases if isinstance(json_response, dict) and "result" in json_response: return json_response return json_response except requests.exceptions.RequestException as e: print(f"API request error: {e}") return {"success": False, "error": str(e)} # Legacy API methods - now using the proper format def get_current_graph(self) -> Dict: """Get information about the current graph""" return self.call_api("logseq.App.getCurrentGraph") def get_all_pages(self) -> List[Dict]: """Get all pages in the graph""" response = self.call_api("logseq.Editor.getAllPages") if isinstance(response, list): return response return response.get("result", []) if isinstance(response, dict) else [] def get_page(self, page_name: str) -> Optional[Dict]: """Get a page by name""" response = self.call_api("logseq.Editor.getPage", [page_name]) if response is None: return None return response.get("result") if isinstance(response, dict) else response def get_page_blocks(self, page_name: str) -> List[Dict]: """Get all blocks for a page""" response = self.call_api("logseq.Editor.getPageBlocksTree", [page_name]) if isinstance(response, list): return response return response.get("result", []) if isinstance(response, dict) else [] def search_blocks(self, query: str) -> List[Dict]: """Search for blocks matching a query""" response = self.call_api("logseq.Editor.search", [query]) if isinstance(response, list): return response return response.get("result", []) if isinstance(response, dict) else [] def create_page(self, page_name: str, properties: Dict = None) -> Dict: """Create a new page""" params = [page_name] if properties: params.append(properties) response = self.call_api("logseq.Editor.createPage", params) if isinstance(response, dict) and "result" in response: return response.get("result") return response def create_block(self, page_name: str, content: str, properties: Dict = None) -> Dict: """Create a new block on a page""" params = [page_name, content] if properties: params.append(properties) response = self.call_api("logseq.Editor.appendBlockInPage", params) if isinstance(response, dict) and "result" in response: return response.get("result") return response def update_block(self, block_id: str, content: str, properties: Dict = None) -> Dict: """Update an existing block""" params = [block_id, content] if properties: params.append(properties) response = self.call_api("logseq.Editor.updateBlock", params) if isinstance(response, dict) and "result" in response: return response.get("result") return response def get_block(self, block_id: str) -> Optional[Dict]: """Get a block by ID""" response = self.call_api("logseq.Editor.getBlock", [block_id]) if response is None: return None return response.get("result") if isinstance(response, dict) else response def get_block_properties(self, block_id: str) -> Dict: """Get properties of a block""" response = self.call_api("logseq.Editor.getBlockProperties", [block_id]) if isinstance(response, dict) and "result" in response: return response.get("result", {}) return response if isinstance(response, dict) else {} def get_page_linked_references(self, page_name: str) -> List[Dict]: """Get linked references to a page""" response = self.call_api("logseq.Editor.getPageLinkedReferences", [page_name]) if isinstance(response, list): return response return response.get("result", []) if isinstance(response, dict) else [] def delete_page(self, page_name: str) -> Dict: """Delete a page from the graph""" response = self.call_api("logseq.Editor.deletePage", [page_name]) if isinstance(response, dict) and "result" in response: return response.get("result") return response def remove_block(self, block_id: str) -> Dict: """Remove a block and its children from the graph""" response = self.call_api("logseq.Editor.removeBlock", [block_id]) if isinstance(response, dict) and "result" in response: return response.get("result") return response def insert_block(self, parent_block_id: str, content: str, properties: Dict = None, before: bool = False) -> Dict: """Insert a new block as a child of the specified parent block""" params = [parent_block_id, content] if properties: params.append(properties) # Choose the appropriate API method based on the 'before' parameter method = "logseq.Editor.insertBlock" if before: method = "logseq.Editor.prependBlock" response = self.call_api(method, params) if isinstance(response, dict) and "result" in response: return response.get("result") return response def move_block(self, block_id: str, target_block_id: str, as_child: bool = False) -> Dict: """Move a block to a new location in the graph""" # Determine the appropriate API method based on the as_child parameter method = "logseq.Editor.moveBlock" # The API expects a structured argument for the move operation move_params = { "srcUUID": block_id, "targetUUID": target_block_id, "isChild": as_child } response = self.call_api(method, [move_params]) if isinstance(response, dict) and "result" in response: return response.get("result") return response

Implementation Reference

Latest Blog Posts

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/mikeysrecipes/logseq-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server