Skip to main content
Glama
test_webdav_search_mcp.py10.5 kB
"""Integration tests for WebDAV search MCP tools.""" import json import logging import uuid import pytest from mcp import ClientSession from nextcloud_mcp_server.client import NextcloudClient logger = logging.getLogger(__name__) pytestmark = pytest.mark.integration def normalize_search_response(data): """Extract results list from SearchFilesResponse. The response is a SearchFilesResponse with a 'results' field containing the list of files. """ if isinstance(data, dict) and "results" in data: return data["results"] else: # Fallback for unexpected format return [] @pytest.fixture async def search_test_files(nc_client: NextcloudClient): """Create test files for WebDAV search testing via MCP.""" test_dir = f"mcp_webdav_search_{uuid.uuid4().hex[:8]}" # Create base directory await nc_client.webdav.create_directory(test_dir) # Create various test files test_files = [ # Text files (f"{test_dir}/search_test1.txt", b"Sample document", "text/plain"), (f"{test_dir}/search_test2.txt", b"Another document", "text/plain"), (f"{test_dir}/search_report.txt", b"Report content", "text/plain"), # Markdown files (f"{test_dir}/search_readme.md", b"# README", "text/markdown"), (f"{test_dir}/search_notes.md", b"# Notes", "text/markdown"), # Images (simulated) (f"{test_dir}/search_image.jpg", b"\xff\xd8\xff fake jpg", "image/jpeg"), (f"{test_dir}/search_photo.png", b"\x89PNG fake png", "image/png"), # PDF (simulated) (f"{test_dir}/search_presentation.pdf", b"%PDF-1.4", "application/pdf"), ] # Write all test files for file_path, content, content_type in test_files: await nc_client.webdav.write_file(file_path, content, content_type) logger.info(f"Created {len(test_files)} test files in {test_dir}") yield test_dir # Cleanup try: await nc_client.webdav.delete_resource(test_dir) logger.info(f"Cleaned up test directory: {test_dir}") except Exception as e: logger.warning(f"Failed to cleanup {test_dir}: {e}") async def test_nc_webdav_find_by_name( nc_mcp_client: ClientSession, search_test_files: str ): """Test nc_webdav_find_by_name MCP tool.""" # Find all .txt files in the test directory result = await nc_mcp_client.call_tool( "nc_webdav_find_by_name", arguments={ "pattern": "search_%.txt", "scope": search_test_files, }, ) # Parse the result content = result.content[0].text files = normalize_search_response(json.loads(content)) logger.info(f"Found {len(files)} files matching 'search_%.txt'") # Should find at least 3 .txt files assert len(files) >= 3, f"Expected at least 3 .txt files, got {len(files)}" # Verify all results end with .txt for file in files: name = file.get("name", "") assert name.endswith(".txt"), f"Expected .txt file, got {name}" assert name.startswith("search_"), ( f"Expected name to start with 'search_', got {name}" ) async def test_nc_webdav_find_by_name_with_limit( nc_mcp_client: ClientSession, search_test_files: str ): """Test nc_webdav_find_by_name with limit parameter.""" # Find files with limit result = await nc_mcp_client.call_tool( "nc_webdav_find_by_name", arguments={ "pattern": "search_%.txt", "scope": search_test_files, "limit": 2, }, ) content = result.content[0].text files = normalize_search_response(json.loads(content)) logger.info(f"Found {len(files)} files with limit=2") # Should return at most 2 results assert len(files) <= 2, f"Expected at most 2 files, got {len(files)}" assert len(files) > 0, "Expected at least 1 file" async def test_nc_webdav_find_by_type_images( nc_mcp_client: ClientSession, search_test_files: str ): """Test nc_webdav_find_by_type for images.""" # Find all images result = await nc_mcp_client.call_tool( "nc_webdav_find_by_type", arguments={ "mime_type": "image/%", "scope": search_test_files, }, ) content = result.content[0].text files = normalize_search_response(json.loads(content)) logger.info(f"Found {len(files)} image files") # Should find at least 2 image files (jpg and png) assert len(files) >= 2, f"Expected at least 2 image files, got {len(files)}" # Verify all results are images for file in files: content_type = file.get("content_type", "") assert content_type.startswith("image/"), ( f"Expected image/* type, got {content_type}" ) async def test_nc_webdav_find_by_type_specific( nc_mcp_client: ClientSession, search_test_files: str ): """Test nc_webdav_find_by_type for specific MIME type.""" # Find PDF files result = await nc_mcp_client.call_tool( "nc_webdav_find_by_type", arguments={ "mime_type": "application/pdf", "scope": search_test_files, }, ) content = result.content[0].text files = normalize_search_response(json.loads(content)) logger.info(f"Found {len(files)} PDF files") # Should find at least 1 PDF assert len(files) >= 1, f"Expected at least 1 PDF file, got {len(files)}" # Verify result is PDF for file in files: content_type = file.get("content_type", "") assert content_type == "application/pdf", ( f"Expected application/pdf, got {content_type}" ) async def test_nc_webdav_search_files_basic( nc_mcp_client: ClientSession, search_test_files: str ): """Test nc_webdav_search_files with basic filters.""" # Search for markdown files result = await nc_mcp_client.call_tool( "nc_webdav_search_files", arguments={ "scope": search_test_files, "name_pattern": "%.md", }, ) content = result.content[0].text files = normalize_search_response(json.loads(content)) logger.info(f"Found {len(files)} markdown files") # Should find at least 2 .md files assert len(files) >= 2, f"Expected at least 2 .md files, got {len(files)}" # Verify all results are .md files for file in files: name = file.get("name", "") assert name.endswith(".md"), f"Expected .md file, got {name}" async def test_nc_webdav_search_files_combined( nc_mcp_client: ClientSession, search_test_files: str ): """Test nc_webdav_search_files with combined filters.""" # Search for text files with specific name pattern result = await nc_mcp_client.call_tool( "nc_webdav_search_files", arguments={ "scope": search_test_files, "name_pattern": "search_test%.txt", "mime_type": "text/plain", }, ) content = result.content[0].text files = normalize_search_response(json.loads(content)) logger.info(f"Found {len(files)} files matching combined filters") # Should find search_test1.txt and search_test2.txt assert len(files) >= 2, f"Expected at least 2 files, got {len(files)}" # Verify all results match both conditions for file in files: name = file.get("name", "") content_type = file.get("content_type", "") assert name.endswith(".txt"), f"Expected .txt file, got {name}" assert name.startswith("search_test"), ( f"Expected 'search_test' prefix, got {name}" ) assert content_type == "text/plain", f"Expected text/plain, got {content_type}" async def test_nc_webdav_search_files_with_limit( nc_mcp_client: ClientSession, search_test_files: str ): """Test nc_webdav_search_files with result limit.""" # Search with limit result = await nc_mcp_client.call_tool( "nc_webdav_search_files", arguments={ "scope": search_test_files, "name_pattern": "search_%", "limit": 3, }, ) content = result.content[0].text files = normalize_search_response(json.loads(content)) logger.info(f"Found {len(files)} files with limit=3") # Should return at most 3 results assert len(files) <= 3, f"Expected at most 3 files, got {len(files)}" assert len(files) > 0, "Expected at least 1 file" async def test_nc_webdav_search_no_results( nc_mcp_client: ClientSession, search_test_files: str ): """Test search that returns no results.""" # Search for non-existent pattern result = await nc_mcp_client.call_tool( "nc_webdav_find_by_name", arguments={ "pattern": "nonexistent_xyz123.txt", "scope": search_test_files, }, ) # Handle case where empty results might return empty content if result.content and len(result.content) > 0: content = result.content[0].text files = normalize_search_response(json.loads(content)) else: files = [] logger.info("Search correctly returned no results") # Should return empty array assert len(files) == 0, f"Expected no results, got {len(files)}" async def test_search_result_properties( nc_mcp_client: ClientSession, search_test_files: str ): """Test that search results include expected properties.""" # Search for a specific file result = await nc_mcp_client.call_tool( "nc_webdav_find_by_name", arguments={ "pattern": "search_readme.md", "scope": search_test_files, }, ) content = result.content[0].text files = normalize_search_response(json.loads(content)) assert len(files) >= 1, "Should find at least one file" file = files[0] # Check for expected properties assert "name" in file, "Should include name property" assert "path" in file, "Should include path property" assert "is_directory" in file, "Should include is_directory property" assert file["is_directory"] is False, "File should not be a directory" # Check for extended properties from search extended_props = ["file_id", "etag", "size", "content_type", "last_modified"] present_props = [prop for prop in extended_props if prop in file] logger.info(f"Search result properties: {list(file.keys())}") assert len(present_props) > 0, f"Should have at least one of {extended_props}"

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/No-Smoke/nextcloud-mcp-comprehensive'

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