search
Read-onlyIdempotent
Find AI-curated articles in Grokipedia's knowledge base for research and information discovery. Returns titles, snippets, and relevance scores to help locate specific content.
Instructions
Search Grokipedia (AI-curated knowledge base) for articles.
Use for: finding Grok-generated articles, discovering AI-synthesized knowledge, research. Returns: title, slug (for get_page), snippet, relevance score, view count. Tips: Use the slug from results with get_page/get_page_content for full articles.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query string to find matching articles | |
| limit | No | Maximum number of results to return (default: 12, max: 50) | |
| offset | No | Pagination offset for results (default: 0) | |
| sort_by | No | Sort results by 'relevance' or 'views' (default: relevance) | relevance |
| min_views | No | Filter to articles with at least this many views (optional) |
Implementation Reference
- grokipedia_mcp/server.py:49-122 (handler)The 'search' tool is defined and registered using the @mcp.tool decorator. It implements search functionality by calling the Grokipedia API client.
@mcp.tool( annotations=ToolAnnotations( readOnlyHint=True, destructiveHint=False, idempotentHint=True ), ) async def search( query: Annotated[str, Field(description="Search query string to find matching articles")], limit: Annotated[int, Field(description="Maximum number of results to return (default: 12, max: 50)", ge=1, le=50)] = 12, offset: Annotated[int, Field(description="Pagination offset for results (default: 0)", ge=0)] = 0, sort_by: Annotated[str, Field(description="Sort results by 'relevance' or 'views' (default: relevance)")] = "relevance", min_views: Annotated[int | None, Field(description="Filter to articles with at least this many views (optional)", ge=0)] = None, ctx: Context[ServerSession, AppContext] | None = None, ) -> CallToolResult: """Search Grokipedia (AI-curated knowledge base) for articles. Use for: finding Grok-generated articles, discovering AI-synthesized knowledge, research. Returns: title, slug (for get_page), snippet, relevance score, view count. Tips: Use the slug from results with get_page/get_page_content for full articles. """ if ctx is None: raise ValueError("Context is required") await ctx.debug(f"Searching for: '{query}' (limit={limit}, offset={offset}, sort_by={sort_by})") try: client = ctx.request_context.lifespan_context.client result = await client.search(query=query, limit=limit * 2, offset=offset) results = result.results if min_views is not None: results = [r for r in results if r.view_count >= min_views] await ctx.debug(f"Filtered to {len(results)} results with min_views >= {min_views}") if sort_by == "views": results = sorted(results, key=lambda x: x.view_count, reverse=True) await ctx.debug("Sorted results by view count") results = results[:limit] await ctx.info(f"Found {len(results)} results for query: '{query}'") text_lines = [f"Found {len(results)} results for '{query}'"] if sort_by == "views": text_lines[0] += " (sorted by views)" if min_views: text_lines[0] += f" (min views: {min_views})" text_lines.append("") for i, item in enumerate(results, 1): text_lines.append(f"{i}. {item.title}") text_lines.append(f" Slug: {item.slug}") text_lines.append(f" Snippet: {item.snippet}") text_lines.append(f" Relevance: {item.relevance_score:.3f}") text_lines.append(f" Views: {item.view_count}") text_lines.append("") return CallToolResult( content=[TextContent(type="text", text="\n".join(text_lines))], structuredContent={"results": [r.model_dump() for r in results]}, ) except GrokipediaBadRequestError as e: await ctx.error(f"Bad request: {e}") raise ValueError(f"Invalid search parameters: {e}") from e except GrokipediaNetworkError as e: await ctx.error(f"Network error: {e}") raise RuntimeError(f"Failed to connect to Grokipedia API: {e}") from e except GrokipediaAPIError as e: await ctx.error(f"API error: {e}") raise RuntimeError(f"Grokipedia API error: {e}") from e