search-posts
Search HackerNews content by keyword with filters for tags, points, comments, dates, and authors to find relevant stories and discussions.
Instructions
Search HackerNews for stories, comments, and other content by keyword.
Supports:
Keyword search across titles, text, and authors
Tag filtering (story, comment, poll, show_hn, ask_hn, front_page, author_USERNAME)
Numeric filters for points, comments, and dates
Pagination with customizable results per page
Advanced filtering with OR logic and multiple conditions
Basic Examples:
Search for AI stories: { "query": "AI", "tags": ["story"] }
Find popular posts: { "query": "Python", "numericFilters": ["points>=100"] }
Filter by author: { "query": "startup", "tags": ["author_pg"] }
Date range: { "query": "startup", "numericFilters": ["created_at_i>1640000000"] }
Advanced Filtering Examples:
High engagement posts: { "query": "programming", "numericFilters": ["points>=100", "num_comments>=50"] }
OR logic for tags: { "query": "web", "tags": ["(story,poll)"] } - returns stories OR polls
Author with filters: { "query": "", "tags": ["author_pg", "story"], "numericFilters": ["points>=50"] }
Multiple conditions: { "query": "AI", "tags": ["story"], "numericFilters": ["points>=200", "num_comments>=100"] }
Numeric Filter Operators: < (less than), <= (less than or equal), = (equal), >= (greater than or equal), > (greater than) Numeric Filter Fields: points, num_comments, created_at_i (Unix timestamp)
Tag Syntax:
Single tag: ["story"] - only stories
Multiple tags (AND): ["story", "show_hn"] - stories that are also show_hn
OR logic: ["(story,poll)"] - stories OR polls
Author filter: ["author_USERNAME"] - posts by specific author
Returns paginated results with hits, total count, and page information.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query text (minimum 1 character) | |
| tags | No | Optional filter tags (e.g., ['story'], ['comment'], ['(story,poll)'] for OR logic, ['author_pg'] for author filter) | |
| numericFilters | No | Optional numeric filters (e.g., ['points>=100'], ['num_comments>=50'], ['created_at_i>1640000000']). Multiple filters use AND logic. | |
| page | No | Page number (0-indexed, default: 0) | |
| hitsPerPage | No | Results per page (1-1000, default: 20) |
Implementation Reference
- src/tools/search-posts.ts:35-60 (handler)The main handler function that executes the 'search-posts' tool: input validation, HN API call, error handling, and result formatting.export async function searchPostsTool(input: unknown): Promise<CallToolResult> { try { // Validate input const params = validateInput(SearchPostsInputSchema, input); // Call HackerNews API const results = await hnApi.search({ query: params.query, tags: params.tags, numericFilters: params.numericFilters, page: params.page, hitsPerPage: params.hitsPerPage, }); // Return success result return createSuccessResult(results); } catch (error) { // Handle validation errors if (error instanceof ZodError) { return handleValidationError(error); } // Handle API errors return handleAPIError(error, "searching posts"); } }
- src/utils/validators.ts:13-24 (schema)Zod schema defining input parameters and validation rules for the search-posts tool.export const SearchPostsInputSchema = z.object({ query: z.string().min(1, "query must contain at least 1 character"), tags: z.array(z.string()).optional(), numericFilters: z.array(z.string()).optional(), page: z.number().int().nonnegative("page must be non-negative").default(0), hitsPerPage: z .number() .int() .min(1, "hitsPerPage must be at least 1") .max(1000, "hitsPerPage must not exceed 1000") .default(20), });
- src/index.ts:45-55 (registration)Registration of searchPostsToolMetadata in the ListToolsRequestHandler, making the tool discoverable.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ searchPostsToolMetadata, getFrontPageTool, getLatestPostsTool, getItemTool, getUserTool, ], }; });
- src/index.ts:66-68 (registration)Dispatch handler in CallToolRequestHandler that routes 'search-posts' calls to the searchPostsTool function.case "search-posts": return await searchPostsTool(args);
- src/tools/search-posts.ts:65-130 (schema)Tool metadata including name, detailed description, and JSON inputSchema used for MCP tool registration and client-side validation.export const searchPostsToolMetadata = { name: "search-posts", description: `Search HackerNews for stories, comments, and other content by keyword. Supports: - Keyword search across titles, text, and authors - Tag filtering (story, comment, poll, show_hn, ask_hn, front_page, author_USERNAME) - Numeric filters for points, comments, and dates - Pagination with customizable results per page - Advanced filtering with OR logic and multiple conditions Basic Examples: - Search for AI stories: { "query": "AI", "tags": ["story"] } - Find popular posts: { "query": "Python", "numericFilters": ["points>=100"] } - Filter by author: { "query": "startup", "tags": ["author_pg"] } - Date range: { "query": "startup", "numericFilters": ["created_at_i>1640000000"] } Advanced Filtering Examples: - High engagement posts: { "query": "programming", "numericFilters": ["points>=100", "num_comments>=50"] } - OR logic for tags: { "query": "web", "tags": ["(story,poll)"] } - returns stories OR polls - Author with filters: { "query": "", "tags": ["author_pg", "story"], "numericFilters": ["points>=50"] } - Multiple conditions: { "query": "AI", "tags": ["story"], "numericFilters": ["points>=200", "num_comments>=100"] } Numeric Filter Operators: < (less than), <= (less than or equal), = (equal), >= (greater than or equal), > (greater than) Numeric Filter Fields: points, num_comments, created_at_i (Unix timestamp) Tag Syntax: - Single tag: ["story"] - only stories - Multiple tags (AND): ["story", "show_hn"] - stories that are also show_hn - OR logic: ["(story,poll)"] - stories OR polls - Author filter: ["author_USERNAME"] - posts by specific author Returns paginated results with hits, total count, and page information.`, inputSchema: { type: "object", properties: { query: { type: "string", description: "Search query text (minimum 1 character)", }, tags: { type: "array", items: { type: "string" }, description: "Optional filter tags (e.g., ['story'], ['comment'], ['(story,poll)'] for OR logic, ['author_pg'] for author filter)", }, numericFilters: { type: "array", items: { type: "string" }, description: "Optional numeric filters (e.g., ['points>=100'], ['num_comments>=50'], ['created_at_i>1640000000']). Multiple filters use AND logic.", }, page: { type: "number", description: "Page number (0-indexed, default: 0)", default: 0, }, hitsPerPage: { type: "number", description: "Results per page (1-1000, default: 20)", default: 20, }, }, required: ["query"], }, };