getShowHNStories
Fetch Show HN submissions from Hacker News to discover new projects and tools shared by developers.
Instructions
Get Show HN stories
Tool call template
This tool declares no required parameters. Add optional parameters from the input schema as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {},
"name": "getShowHNStories"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Number of stories to return (default: 10, max: 30) |
Implementation Reference
- src/tools.ts:242-300 (handler)The complete tool object for getShowHNStories, including the execute handler function that implements the core logic: fetching Show HN story IDs from /showstories, retrieving items, formatting, and returning structured JSON response.
{ name: "getShowHNStories", description: "Get Show HN stories", inputSchema: { type: "object", properties: { limit: { type: "number", description: "Number of stories to return (default: 10, max: 30)", default: 10, }, }, }, execute: async (args: any) => { const limit = Math.min(args.limit || 10, 30); const showIds = await fetchFromAPI<number[]>("/showstories"); if (!showIds) { return { content: [ { type: "text", text: JSON.stringify({ error: "Failed to fetch Show HN stories", }), }, ], }; } const stories = await fetchMultipleItems(showIds, limit); const formattedStories = stories.map((story) => ({ id: story.id, title: story.title, url: story.url, score: story.score, author: story.by, comments: story.descendants || 0, time: story.time ? formatTime(story.time) : "unknown", hnUrl: `https://news.ycombinator.com/item?id=${story.id}`, })); return { content: [ { type: "text", text: JSON.stringify( { message: `Latest ${limit} Show HN stories`, stories: formattedStories, }, null, 2 ), }, ], }; }, }, - src/index.ts:44-65 (registration)MCP server handles tools/list to register available tools (including getShowHNStories) and tools/call to execute the selected tool by name.
sendResponse(json.id, { tools: tools.map((tool) => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema, })), }); } if (json.method === "tools/call") { const tool = tools.find((tool) => tool.name === json.params.name); if (tool) { const toolResponse = await tool.execute(json.params.arguments); sendResponse(json.id, toolResponse); } else { sendResponse(json.id, { error: { code: -32602, message: `MCP error -32602: Tool ${json.params.name} not found`, }, }); } } - src/fetch-actions.ts:9-27 (helper)fetchFromAPI helper function used by the handler to fetch '/showstories' IDs and individual story items from the Hacker News API, with caching support.
export async function fetchFromAPI<T>(endpoint: string): Promise<T | null> { const cacheKey = endpoint; const cached = getCached<T>(cacheKey); if (cached) return cached; try { const response = await fetch( `https://hacker-news.firebaseio.com/v0${endpoint}.json` ); if (!response.ok) throw new Error(`HTTP ${response.status}`); const data = await response.json(); setCache(cacheKey, data); return data; } catch (error) { console.error(`Error fetching ${endpoint}:`, error); return null; } } - src/helpers.ts:23-35 (helper)formatTime utility function used to format story timestamps into human-readable relative time (e.g., '2h ago').
export function formatTime(timestamp: number): string { const date = new Date(timestamp * 1000); const now = new Date(); const diff = now.getTime() - date.getTime(); const minutes = Math.floor(diff / (1000 * 60)); const hours = Math.floor(diff / (1000 * 60 * 60)); const days = Math.floor(diff / (1000 * 60 * 60 * 24)); if (minutes < 60) return `${minutes}m ago`; if (hours < 24) return `${hours}h ago`; return `${days}d ago`; } - src/fetch-actions.ts:30-44 (helper)fetchMultipleItems helper used to parallel-fetch and filter story items by IDs, excluding deleted/dead items.
export async function fetchMultipleItems( ids: number[], maxItems = 30 ): Promise<HackerNewsItem[]> { const limitedIds = ids.slice(0, maxItems); const promises = limitedIds.map((id) => fetchFromAPI<HackerNewsItem>(`/item/${id}`) ); const results = await Promise.all(promises); return results.filter( (item): item is HackerNewsItem => item !== null && !item.deleted && !item.dead ); }