search_poems
Find poems by searching titles, content, and notes with filters for states, forms, and tags to locate specific poetry matching your criteria.
Instructions
Search for poems matching criteria.
Args: query: Text to search for in titles, content, and notes states: Filter by states (e.g., ["completed", "fledgeling"]) forms: Filter by forms (e.g., ["free_verse", "prose_poem"]) tags: Filter by tags (poems must have all specified tags) limit: Maximum number of results to return include_content: Whether to include full poem text in results
Returns: SearchResult with matched poems and query metadata
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| states | No | ||
| forms | No | ||
| tags | No | ||
| limit | No | ||
| include_content | No |
Implementation Reference
- src/poetry_mcp/server.py:116-189 (handler)The core handler function for the 'search_poems' tool. It performs text search, applies filters for states, forms, and tags, sorts by relevance, limits results, and returns a SearchResult. Registered via @mcp.tool() decorator.@mcp.tool() async def search_poems( query: str, states: Optional[List[str]] = None, forms: Optional[List[str]] = None, tags: Optional[List[str]] = None, limit: int = 20, include_content: bool = False ) -> SearchResult: """ Search for poems matching criteria. Args: query: Text to search for in titles, content, and notes states: Filter by states (e.g., ["completed", "fledgeling"]) forms: Filter by forms (e.g., ["free_verse", "prose_poem"]) tags: Filter by tags (poems must have all specified tags) limit: Maximum number of results to return include_content: Whether to include full poem text in results Returns: SearchResult with matched poems and query metadata """ import time start_time = time.perf_counter() cat = get_catalog() # Start with text search if query provided if query: results = cat.index.search_content(query, case_sensitive=False) else: # No query, start with all poems results = cat.index.all_poems.copy() # Apply state filter if states: results = [p for p in results if p.state in states] # Apply form filter if forms: results = [p for p in results if p.form in forms] # Apply tag filter (must have all tags) if tags: results = [ p for p in results if all(tag.lower() in [t.lower() for t in p.tags] for tag in tags) ] # Sort by relevance (poems with more tag matches first) if tags: def relevance_score(poem: Poem) -> int: return sum(1 for tag in tags if tag.lower() in [t.lower() for t in poem.tags]) results.sort(key=relevance_score, reverse=True) # Limit results total_matches = len(results) results = results[:limit] # Remove content if not requested if not include_content: results = [ Poem(**{**p.model_dump(), 'content': None}) for p in results ] query_time_ms = (time.perf_counter() - start_time) * 1000 return SearchResult( poems=results, total_matches=total_matches, query_time_ms=query_time_ms )
- Pydantic model defining the output schema for the search_poems tool, including list of poems, total matches, and query time.class SearchResult(BaseModel): """ Result from search_poems operation. Contains matched poems and query metadata. """ poems: list[Poem] = Field( ..., description="List of poems matching search criteria" ) total_matches: int = Field( ..., description="Total number of poems matching query (may be > len(poems) if limited)" ) query_time_ms: float = Field( ..., description="Time taken to execute query in milliseconds" ) class Config: """Pydantic configuration.""" json_schema_extra = { "example": { "poems": [ { "id": "second-bridge", "title": "Second Bridge Out Old Route 12", "state": "completed", "form": "free_verse", "tags": ["water", "memory"] } ], "total_matches": 23, "query_time_ms": 45.2 } }
- src/poetry_mcp/server.py:116-116 (registration)The @mcp.tool() decorator registers the search_poems function as an MCP tool.@mcp.tool()