get_stories
Fetch structured Hacker News stories by type (top, new, ask, show, jobs) and limit results to a specified number. Designed to provide parsed HTML content from news.ycombinator.com.
Instructions
Get stories from Hacker News
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Number of stories to return (max 30) | |
| type | No | Type of stories to fetch (top, new, ask, show, jobs) | top |
Implementation Reference
- src/index.ts:128-166 (handler)Implements the execution logic for the 'get_stories' tool by handling CallToolRequest, validating parameters, fetching stories, and returning JSON response.this.server.setRequestHandler(CallToolRequestSchema, async (request) => { if (request.params.name !== 'get_stories') { throw new McpError( ErrorCode.MethodNotFound, `Unknown tool: ${request.params.name}` ); } const args = request.params.arguments as { type?: string; limit?: number }; const type = args.type || 'top'; const limit = Math.min(args.limit || 10, 30); if (!isValidStoryType(type)) { throw new McpError( ErrorCode.InvalidParams, `Invalid story type: ${type}. Must be one of: top, new, ask, show, jobs` ); } try { const stories = await this.fetchStories(type); return { content: [ { type: 'text', text: JSON.stringify(stories.slice(0, limit), null, 2) } ] }; } catch (error) { if (error instanceof McpError) { throw error; } throw new McpError( ErrorCode.InternalError, `Failed to fetch stories: ${error}` ); } });
- src/index.ts:54-98 (helper)Fetches and parses Hacker News stories using axios and cheerio, extracting title, url, points, author, time, comments, and rank.private async fetchStories(type: string = 'top'): Promise<Story[]> { try { const url = type === 'top' ? this.baseUrl : `${this.baseUrl}/${type}`; const response = await axios.get(url); const $ = cheerio.load(response.data); const stories: Story[] = []; $('.athing').each((i, elem) => { const titleRow = $(elem); const metadataRow = titleRow.next(); const rank = parseInt(titleRow.find('.rank').text(), 10); const titleElement = titleRow.find('.titleline > a').first(); const title = titleElement.text(); const url = titleElement.attr('href'); const sitebit = titleRow.find('.sitebit'); const points = parseInt(metadataRow.find('.score').text(), 10) || 0; const author = metadataRow.find('.hnuser').text(); const time = metadataRow.find('.age').attr('title') || ''; const commentText = metadataRow.find('a').last().text(); const commentCount = parseInt(commentText.split(' ')[0]) || 0; stories.push({ title, url: url?.startsWith('item?id=') ? `${this.baseUrl}/${url}` : url, points, author, time, commentCount, rank }); }); return stories; } catch (error) { if (axios.isAxiosError(error)) { throw new McpError( ErrorCode.InternalError, `Failed to fetch stories: ${error.message}` ); } throw error; } }
- src/index.ts:101-127 (registration)Registers the 'get_stories' tool in the ListToolsRequest handler with name, description, and input schema.this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ { name: 'get_stories', description: 'Get stories from Hacker News', inputSchema: { type: 'object', properties: { type: { type: 'string', description: 'Type of stories to fetch (top, new, ask, show, jobs)', enum: ['top', 'new', 'ask', 'show', 'jobs'], default: 'top' }, limit: { type: 'number', description: 'Number of stories to return (max 30)', minimum: 1, maximum: 30, default: 10 } } } } ] }));
- src/index.ts:106-123 (schema)Input schema definition for the 'get_stories' tool parameters: type (enum) and limit (number).inputSchema: { type: 'object', properties: { type: { type: 'string', description: 'Type of stories to fetch (top, new, ask, show, jobs)', enum: ['top', 'new', 'ask', 'show', 'jobs'], default: 'top' }, limit: { type: 'number', description: 'Number of stories to return (max 30)', minimum: 1, maximum: 30, default: 10 } } }
- src/index.ts:13-21 (schema)TypeScript interface defining the structure of a Story object returned by the tool.interface Story { title: string; url?: string; points: number; author: string; time: string; commentCount: number; rank: number; }