Skip to main content
Glama

search_by_property

Search for notes by frontmatter property values to quickly locate specific content based on metadata fields in your Obsidian vault.

Instructions

Search for notes by frontmatter property (metadata field)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
limitNo
property_nameYes
property_valueNo

Implementation Reference

  • Primary MCP tool handler for 'search_by_property'. Validates inputs, invokes the VaultSearch method, formats results as markdown list.
        name="search_by_property",
        description="Search for notes by frontmatter property (metadata field)",
    )
    async def search_by_property(property_name: str, property_value: str = "", limit: int = 50) -> str:
        """
        Search for notes by frontmatter property.
    
        Args:
            property_name: Name of the frontmatter property to search
            property_value: Optional value to match (empty to find all notes with this property)
            limit: Maximum number of results (default: 50)
    
        Returns:
            Formatted list of notes matching the property
        """
        if not property_name or not property_name.strip():
            return "Error: Property name cannot be empty"
        if limit <= 0 or limit > 1000:
            return "Error: Limit must be between 1 and 1000"
    
        context = _get_context()
    
        try:
            # Convert empty string to None for "any value" search
            value = property_value if property_value else None
            results = await context.search.search_by_property(property_name, value, limit=limit)
    
            if not results:
                if value:
                    return f"No notes found with property '{property_name}' = '{value}'"
                else:
                    return f"No notes found with property '{property_name}'"
    
            # Format results
            if value:
                output = f"Found {len(results)} note(s) with '{property_name}' = '{value}':\n\n"
            else:
                output = f"Found {len(results)} note(s) with property '{property_name}':\n\n"
    
            for i, result in enumerate(results, 1):
                output += f"{i}. **{result.name}**\n"
                output += f"   Path: `{result.path}`\n"
                if result.snippet:
                    output += f"   {result.snippet}\n"
                output += "\n"
    
            return output
    
        except Exception as e:
            logger.exception(f"Error searching by property: {property_name}")
            return f"Error searching by property: {e}"
  • Core implementation logic in VaultSearch class that scans notes, matches frontmatter properties, scores results, and returns SearchResult list.
    async def search_by_property(
        self, property_name: str, property_value: str | None = None, limit: int = 50
    ) -> list[SearchResult]:
        """
        Search for notes by frontmatter property.
    
        Args:
            property_name: Name of the frontmatter property
            property_value: Optional value to match (if None, matches any note with the property)
            limit: Maximum number of results
    
        Returns:
            List of search results
        """
        results: list[SearchResult] = []
        notes = self.vault.list_notes(limit=None)
    
        for note_meta in notes:
            if len(results) >= limit:
                break
    
            try:
                note = await self.vault.read_note(note_meta.path)
    
                if not note.frontmatter:
                    continue
    
                # Check if property exists
                if property_name not in note.frontmatter:
                    continue
    
                prop_val = note.frontmatter[property_name]
    
                # If no value specified, just match presence
                if property_value is None:
                    score = 1.0
                else:
                    # Check if value matches
                    if isinstance(prop_val, list):
                        # Check if value is in list
                        if property_value in prop_val or property_value in str(prop_val):
                            score = 2.0
                        else:
                            continue
                    elif str(prop_val).lower() == property_value.lower():
                        score = 5.0  # Exact match
                    elif property_value.lower() in str(prop_val).lower():
                        score = 2.0  # Partial match
                    else:
                        continue
    
                # Create snippet from frontmatter
                snippet = f"{property_name}: {prop_val}"
    
                results.append(
                    SearchResult(
                        path=note_meta.path, name=note_meta.name, score=score, snippet=snippet
                    )
                )
    
            except (OSError, UnicodeDecodeError) as e:
                logger.debug(f"Failed to read note {note_meta.path}: {e}")
                continue
    
        results.sort(key=lambda r: r.score, reverse=True)
        return results[:limit]
  • Dataclass defining the structure of search results used by search_by_property.
    @dataclass(slots=True, frozen=True)
    class SearchResult:
        """A search result with context (immutable)."""
    
        path: str
        name: str
        score: float
        snippet: str | None = None
        matched_tags: list[str] | None = None
  • MCP tool registration decorator specifying the tool name and description.
        name="search_by_property",
        description="Search for notes by frontmatter property (metadata field)",
    )
    async def search_by_property(property_name: str, property_value: str = "", limit: int = 50) -> str:

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/getglad/obsidian_mcp'

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