Skip to main content
Glama
search_by_metadata.py7.64 kB
""" Search by metadata tool for Alfresco MCP Server. Each tool is self-contained with its own validation, business logic, and env handling. """ import logging from typing import Optional from fastmcp import Context from ...utils.connection import ensure_connection from ...utils.json_utils import safe_format_output logger = logging.getLogger(__name__) async def search_by_metadata_impl( term: str = "", creator: str = "", content_type: str = "", max_results: int = 25, ctx: Optional[Context] = None ) -> str: """Search for content in Alfresco by metadata fields. Args: term: Search term to include (primary search parameter) creator: Creator username to filter by content_type: Content type to filter by (e.g., "cm:content", "cm:folder") max_results: Maximum number of results to return (default: 25) ctx: MCP context for progress reporting Returns: Formatted search results with metadata """ # Parameter validation and extraction try: # Extract parameters with fallback handling if hasattr(creator, 'value'): actual_creator = str(creator.value) else: actual_creator = str(creator) if hasattr(content_type, 'value'): actual_content_type = str(content_type.value) else: actual_content_type = str(content_type) if hasattr(term, 'value'): actual_term = str(term.value) else: actual_term = str(term) if hasattr(max_results, 'value'): actual_max_results = int(max_results.value) else: actual_max_results = int(max_results) # Clean and normalize for display (preserve Unicode characters) safe_creator_display = str(actual_creator) safe_content_type_display = str(actual_content_type) safe_term_display = str(actual_term) except Exception as e: logger.error(f"Parameter extraction error: {e}") return f"ERROR: Parameter error: {str(e)}" if ctx: await ctx.info(safe_format_output(f"Searching by metadata in Alfresco...")) await ctx.report_progress(0.0) try: # Get all clients that ensure_connection() already created master_client = await ensure_connection() # Import search_utils from python_alfresco_api.utils import search_utils # Access the search client that was already created search_client = master_client.search logger.info(f"Searching Alfresco by metadata - creator: '{safe_creator_display}', type: '{safe_content_type_display}', term: '{safe_term_display}'") if ctx: await ctx.report_progress(0.3) # Build query using search_utils.build_query() utility search_query = search_utils.build_query( term=actual_term if actual_term.strip() else None, content_type=actual_content_type if actual_content_type.strip() else None, creator=actual_creator if actual_creator.strip() else None ) # If no parameters provided, search everything if not search_query or search_query.strip() == "": search_query = "*" # Execute search using existing search client if ctx: await ctx.report_progress(0.5) try: # Use correct working pattern: search_utils.simple_search with existing search_client search_results = search_utils.simple_search(search_client, search_query, max_items=actual_max_results) if not search_results or not hasattr(search_results, 'list_'): return safe_format_output(f"ERROR: Search failed - invalid response from Alfresco") except Exception as e: logger.error(f"Search failed: {e}") return safe_format_output(f"ERROR: Search failed: {str(e)}") # Process results using correct pattern entries = [] if hasattr(search_results, 'list_') and search_results.list_ and hasattr(search_results.list_, 'entries'): entries = search_results.list_.entries if search_results.list_ else [] if ctx: await ctx.report_progress(1.0) # Process final results if entries: logger.info(f"Found {len(entries)} search results") result_text = f"Found {len(entries)} item(s) matching the metadata criteria:\n\n" for i, entry in enumerate(entries, 1): # Debug: Log the entry structure logger.debug(f"Entry {i} type: {type(entry)}, content: {entry}") # Handle different possible entry structures node = None if isinstance(entry, dict): if 'entry' in entry: node = entry['entry'] elif 'name' in entry: # Direct node structure node = entry else: logger.warning(f"Unknown entry structure: {entry}") continue elif hasattr(entry, 'entry'): # ResultSetRowEntry object node = entry.entry else: logger.warning(f"Entry is not a dict or ResultSetRowEntry: {type(entry)}") continue if node: # Handle both dict and ResultNode objects if isinstance(node, dict): name = str(node.get('name', 'Unknown')) node_id = str(node.get('id', 'Unknown')) node_type_actual = str(node.get('nodeType', 'Unknown')) created_at = str(node.get('createdAt', 'Unknown')) else: # ResultNode object - access attributes directly name = str(getattr(node, 'name', 'Unknown')) node_id = str(getattr(node, 'id', 'Unknown')) node_type_actual = str(getattr(node, 'node_type', 'Unknown')) created_at = str(getattr(node, 'created_at', 'Unknown')) # Clean JSON-friendly formatting (no markdown syntax) # Apply safe formatting to individual fields to prevent emoji encoding issues safe_name = safe_format_output(name) safe_node_id = safe_format_output(node_id) safe_node_type = safe_format_output(node_type_actual) safe_created_at = safe_format_output(created_at) result_text += f"{i}. {safe_name}\n" result_text += f" - ID: {safe_node_id}\n" result_text += f" - Type: {safe_node_type}\n" result_text += f" - Created: {safe_created_at}\n\n" return safe_format_output(result_text) else: # Simple "0" for zero results as requested return "0" except Exception as e: # Preserve Unicode characters in error messages error_msg = f"ERROR: Metadata search failed: {str(e)}" if ctx: await ctx.error(safe_format_output(error_msg)) return safe_format_output(error_msg) if ctx: await ctx.info(safe_format_output("Metadata search completed!"))

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/stevereiner/python-alfresco-mcp-server'

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