Skip to main content
Glama

MCP server for LogSeq

by ergut
test_mcp_server.py10.3 kB
import pytest import asyncio from unittest.mock import patch, Mock, AsyncMock from mcp.types import Tool, TextContent from mcp_logseq.server import app, tool_handlers, add_tool_handler, get_tool_handler class TestMCPServerIntegration: """Integration tests for the MCP server.""" def test_tool_handlers_registration(self): """Test that all tool handlers are properly registered.""" expected_tools = [ "create_page", "list_pages", "get_page_content", "delete_page", "update_page", "search" ] # Verify all expected tools are registered for tool_name in expected_tools: assert tool_name in tool_handlers handler = get_tool_handler(tool_name) assert handler is not None assert hasattr(handler, 'run_tool') assert hasattr(handler, 'get_tool_description') def test_get_tool_handler_existing(self): """Test retrieving an existing tool handler.""" handler = get_tool_handler("create_page") assert handler is not None assert handler.name == "create_page" def test_get_tool_handler_non_existing(self): """Test retrieving a non-existing tool handler.""" handler = get_tool_handler("non_existing_tool") assert handler is None def test_list_tools_handler_count(self): """Test that we have the expected number of tool handlers.""" # We should have 6 registered tool handlers assert len(tool_handlers) == 6 # Verify specific tool names are present expected_names = [ "create_page", "list_pages", "get_page_content", "delete_page", "update_page", "search" ] for name in expected_names: assert name in tool_handlers # Verify each handler can generate a tool description for handler in tool_handlers.values(): tool_desc = handler.get_tool_description() assert isinstance(tool_desc, Tool) assert hasattr(tool_desc, 'name') assert hasattr(tool_desc, 'description') assert hasattr(tool_desc, 'inputSchema') @patch.dict('os.environ', {'LOGSEQ_API_TOKEN': 'test_token'}) @patch('mcp_logseq.tools.logseq.LogSeq') def test_call_tool_success_integration(self, mock_logseq_class): """Test successful tool call execution through handler.""" # Setup mock mock_api = Mock() mock_logseq_class.return_value = mock_api # Test create_page tool directly through handler handler = get_tool_handler("create_page") result = handler.run_tool({ "title": "Test Page", "content": "Test content" }) # Verify result assert isinstance(result, list) assert len(result) == 1 assert isinstance(result[0], TextContent) assert "Successfully created page 'Test Page'" in result[0].text # Verify API was called mock_api.create_page.assert_called_once_with("Test Page", "Test content") def test_call_tool_unknown_tool_integration(self): """Test calling an unknown tool through handler system.""" handler = get_tool_handler("unknown_tool") assert handler is None @patch.dict('os.environ', {'LOGSEQ_API_TOKEN': 'test_token'}) @patch('mcp_logseq.tools.logseq.LogSeq') def test_call_tool_handler_error_integration(self, mock_logseq_class): """Test tool call when handler raises an exception.""" # Setup mock to raise exception mock_api = Mock() mock_api.create_page.side_effect = Exception("API Error") mock_logseq_class.return_value = mock_api handler = get_tool_handler("create_page") with pytest.raises(Exception, match="API Error"): handler.run_tool({ "title": "Test Page", "content": "Test content" }) @patch.dict('os.environ', {'LOGSEQ_API_TOKEN': 'test_token'}) @patch('mcp_logseq.tools.logseq.LogSeq') def test_list_pages_tool_integration(self, mock_logseq_class): """Test list_pages tool end-to-end.""" # Setup mock mock_api = Mock() mock_api.list_pages.return_value = [ {"originalName": "Page 1", "journal?": False}, {"originalName": "Page 2", "journal?": False} ] mock_logseq_class.return_value = mock_api handler = get_tool_handler("list_pages") result = handler.run_tool({"include_journals": False}) # Verify result structure assert len(result) == 1 text = result[0].text assert "Page 1" in text assert "Page 2" in text assert "Total pages: 2" in text @patch.dict('os.environ', {'LOGSEQ_API_TOKEN': 'test_token'}) @patch('mcp_logseq.tools.logseq.LogSeq') def test_get_page_content_tool_integration(self, mock_logseq_class): """Test get_page_content tool end-to-end.""" # Setup mock mock_api = Mock() mock_api.get_page_content.return_value = { "page": { "originalName": "Test Page", "properties": {"priority": "high"} }, "blocks": [{"content": "Test content"}] } mock_logseq_class.return_value = mock_api handler = get_tool_handler("get_page_content") result = handler.run_tool({ "page_name": "Test Page", "format": "text" }) # Verify result structure assert len(result) == 1 text = result[0].text assert "# Test Page" in text assert "priority: high" in text assert "Test content" in text @patch.dict('os.environ', {'LOGSEQ_API_TOKEN': 'test_token'}) @patch('mcp_logseq.tools.logseq.LogSeq') def test_search_tool_integration(self, mock_logseq_class): """Test search tool end-to-end.""" # Setup mock mock_api = Mock() mock_api.search_content.return_value = { "blocks": [{"block/content": "Found content"}], "pages": ["Matching Page"], "pages-content": [], "files": [], "has-more?": False } mock_logseq_class.return_value = mock_api handler = get_tool_handler("search") result = handler.run_tool({"query": "test search"}) # Verify result structure assert len(result) == 1 text = result[0].text assert "Search Results for 'test search'" in text assert "Found content" in text assert "Matching Page" in text @patch.dict('os.environ', {'LOGSEQ_API_TOKEN': 'test_token'}) @patch('mcp_logseq.tools.logseq.LogSeq') def test_delete_page_tool_integration(self, mock_logseq_class): """Test delete_page tool end-to-end.""" # Setup mock mock_api = Mock() mock_api.delete_page.return_value = {"success": True} mock_logseq_class.return_value = mock_api handler = get_tool_handler("delete_page") result = handler.run_tool({"page_name": "Test Page"}) # Verify result structure assert len(result) == 1 text = result[0].text assert "✅ Successfully deleted page 'Test Page'" in text assert "🗑️ Page 'Test Page' has been permanently removed" in text @patch.dict('os.environ', {'LOGSEQ_API_TOKEN': 'test_token'}) @patch('mcp_logseq.tools.logseq.LogSeq') def test_update_page_tool_integration(self, mock_logseq_class): """Test update_page tool end-to-end.""" # Setup mock mock_api = Mock() mock_api.update_page.return_value = { "updates": [("content", {"success": True})], "page": "Test Page" } mock_logseq_class.return_value = mock_api handler = get_tool_handler("update_page") result = handler.run_tool({ "page_name": "Test Page", "content": "New content" }) # Verify result structure assert len(result) == 1 text = result[0].text assert "✅ Successfully updated page 'Test Page'" in text assert "📄 Content appended" in text def test_add_tool_handler_custom(self): """Test adding a custom tool handler.""" from mcp_logseq.tools import ToolHandler from mcp.types import Tool, TextContent class CustomToolHandler(ToolHandler): def __init__(self): super().__init__("custom_tool") def get_tool_description(self): return Tool( name=self.name, description="Custom test tool", inputSchema={"type": "object", "properties": {}, "required": []} ) def run_tool(self, args: dict): return [TextContent(type="text", text="Custom tool result")] # Add custom handler custom_handler = CustomToolHandler() original_count = len(tool_handlers) add_tool_handler(custom_handler) # Verify it was added assert len(tool_handlers) == original_count + 1 assert "custom_tool" in tool_handlers assert get_tool_handler("custom_tool") == custom_handler # Clean up del tool_handlers["custom_tool"] def test_tool_handler_interface_compliance(self): """Test that all registered tool handlers implement the required interface.""" for name, handler in tool_handlers.items(): # Check required methods exist assert hasattr(handler, 'get_tool_description') assert hasattr(handler, 'run_tool') assert hasattr(handler, 'name') # Check name attribute matches assert handler.name == name # Check get_tool_description returns a Tool tool_desc = handler.get_tool_description() assert isinstance(tool_desc, Tool) assert tool_desc.name == name

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

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