search_posts
Find relevant HackerNews posts by searching with keywords, filtering by author, score, or date range, and retrieving results within specified limits.
Instructions
Search and filter HackerNews posts by keywords, author, score, and date range
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| author | No | ||
| endTime | No | ||
| limit | No | ||
| minScore | No | ||
| query | No | ||
| startTime | No |
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"author": {
"type": "string"
},
"endTime": {
"type": "number"
},
"limit": {
"default": 20,
"maximum": 100,
"minimum": 1,
"type": "number"
},
"minScore": {
"type": "number"
},
"query": {
"type": "string"
},
"startTime": {
"type": "number"
}
},
"type": "object"
}
Implementation Reference
- src/tools/index.ts:25-67 (handler)The handler function that executes the 'search_posts' tool logic: constructs SearchParams, invokes hnClient.searchStories, formats results as structured JSON, and handles errors.async ({ query, author, minScore, startTime, endTime, limit }) => { try { const searchParams: SearchParams = { query, author, minScore, startTime, endTime, limit: limit || 20 }; const posts = await hnClient.searchStories(searchParams); return { content: [{ type: "text", text: JSON.stringify({ search_params: searchParams, result_count: posts.length, posts: posts.map(post => ({ id: post.id, title: post.title, by: post.by, score: post.score, time: post.time, url: post.url, descendants: post.descendants })) }, null, 2) }] }; } catch (error) { logger.error("Failed to search posts:", error); return { content: [{ type: "text", text: `Error searching posts: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } );
- src/tools/index.ts:13-23 (schema)Input schema using Zod for validating tool parameters: query, author, minScore, time ranges, and limit.{ title: "Search HackerNews Posts", description: "Search and filter HackerNews posts by keywords, author, score, and date range", inputSchema: { query: z.string().optional(), author: z.string().optional(), minScore: z.number().optional(), startTime: z.number().optional(), endTime: z.number().optional(), limit: z.number().min(1).max(100).default(20).optional() }
- src/tools/index.ts:12-67 (registration)Registers the 'search_posts' tool with the MCP server in setupTools, providing name, schema, and handler."search_posts", { title: "Search HackerNews Posts", description: "Search and filter HackerNews posts by keywords, author, score, and date range", inputSchema: { query: z.string().optional(), author: z.string().optional(), minScore: z.number().optional(), startTime: z.number().optional(), endTime: z.number().optional(), limit: z.number().min(1).max(100).default(20).optional() } }, async ({ query, author, minScore, startTime, endTime, limit }) => { try { const searchParams: SearchParams = { query, author, minScore, startTime, endTime, limit: limit || 20 }; const posts = await hnClient.searchStories(searchParams); return { content: [{ type: "text", text: JSON.stringify({ search_params: searchParams, result_count: posts.length, posts: posts.map(post => ({ id: post.id, title: post.title, by: post.by, score: post.score, time: post.time, url: post.url, descendants: post.descendants })) }, null, 2) }] }; } catch (error) { logger.error("Failed to search posts:", error); return { content: [{ type: "text", text: `Error searching posts: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } );
- src/api/client.ts:187-200 (helper)Supporting method in HackerNewsClient that performs the actual story search: fetches top stories, retrieves items, filters by parameters, and limits results. Called by the tool handler.async searchStories(params: SearchParams): Promise<HackerNewsItem[]> { const topStories = await this.getTopStories(); const storyLimit = Math.min(params.limit || 50, 100); // Limit to avoid too many API calls const stories = await Promise.all( topStories.slice(0, storyLimit * 2).map(id => this.getItem(id)) ); const validStories = stories.filter((story): story is HackerNewsItem => story !== null && story.type === "story" ); return this.filterStories(validStories, params).slice(0, storyLimit); }