search_notes
Search through notes using keywords, categories, or tags to find relevant information in your knowledge base.
Instructions
Search through all notes by query, category path, or tags
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Search term (searches title, content, tags) - case insensitive | |
| category_path | No | Optional category path filter (e.g., 'work/clients'). Searches in this path and all subcategories by default. | |
| tags | No | Optional comma-separated tags to filter by (matches any) | |
| recursive | No | If true, search in subcategories too (default: true) |
Implementation Reference
- src/knowledge_base_mcp/server.py:443-464 (handler)The handler function that executes the search_notes MCP tool. Parses input arguments and calls the search engine to perform the search.async def handle_search_notes(arguments: dict) -> list[TextContent]: """Handle search_notes tool call.""" query = arguments.get("query", "") category_path = arguments.get("category_path") tags_str = arguments.get("tags") recursive = arguments.get("recursive", True) # Parse tags tags = None if tags_str: tags = [tag.strip() for tag in tags_str.split(",") if tag.strip()] # Search result = search_engine.search_formatted( query=query, category_path=category_path, tags=tags, recursive=recursive ) return [TextContent(type="text", text=result)]
- src/knowledge_base_mcp/server.py:165-191 (registration)Registers the search_notes tool in the MCP server's list_tools() with its input schema and description.Tool( name="search_notes", description="Search through all notes by query, category path, or tags", inputSchema={ "type": "object", "properties": { "query": { "type": "string", "description": "Search term (searches title, content, tags) - case insensitive", "default": "", }, "category_path": { "type": "string", "description": "Optional category path filter (e.g., 'work/clients'). Searches in this path and all subcategories by default.", }, "tags": { "type": "string", "description": "Optional comma-separated tags to filter by (matches any)", }, "recursive": { "type": "boolean", "description": "If true, search in subcategories too (default: true)", "default": True, }, }, }, ),
- src/knowledge_base_mcp/server.py:302-303 (handler)Dispatches tool calls to the search_notes handler in the main call_tool function.elif name == "search_notes": return await handle_search_notes(arguments)
- Core search logic in KnowledgeBaseSearch class: retrieves notes, applies filters, calculates relevance, and sorts results.def search( self, query: str = "", category_path: Optional[str] = None, tags: Optional[list[str]] = None, recursive: bool = True ) -> list[SearchResult]: """ Search through all notes. Args: query: Search term (searches title, content, tags) - case insensitive category_path: Optional category path filter (e.g., "work/clients") tags: Optional list of tags to filter by (matches any) recursive: If True, search in subcategories too (default: True) Returns: List of SearchResult objects sorted by relevance """ # Get all notes (potentially filtered by category path) all_notes = self.storage.list_notes( category_path=category_path, recursive=recursive ) results = [] for note in all_notes: # Apply tag filter if specified (match any tag) if tags: note_tags_lower = [t.lower() for t in note.frontmatter.tags] search_tags_lower = [t.lower() for t in tags] if not any(tag in note_tags_lower for tag in search_tags_lower): continue # Calculate relevance score relevance = self._calculate_relevance(note, query) # Include all notes if no query, or only matches if query provided if not query or relevance > 0: results.append(SearchResult(note=note, relevance_score=relevance)) # Sort by relevance (highest first) results.sort(key=lambda r: r.relevance_score, reverse=True) return results
- Helper method called by the handler to perform the formatted search and return the text output.def search_formatted( self, query: str = "", category_path: Optional[str] = None, tags: Optional[list[str]] = None, recursive: bool = True ) -> str: """ Search and return formatted results as a string. Args: query: Search term category_path: Optional category path filter (e.g., "work/clients") tags: Optional list of tags to filter by recursive: If True, search in subcategories too (default: True) Returns: Formatted search results string """ results = self.search( query=query, category_path=category_path, tags=tags, recursive=recursive ) if not results: return "No results found." # Format results output_lines = [f"Found {len(results)} result(s):\n"] for result in results: output_lines.append(str(result)) output_lines.append("") # Blank line between results return "\n".join(output_lines)