hn_comments
Retrieve comments for a Hacker News story using its story ID or its index from the last fetched list.
Instructions
Get comments for a story (by story ID or index from last story list)
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| story_id | No | The ID of the story to get comments for | |
| story_index | No | The index (1-based) of the story from the last fetched list |
Implementation Reference
- index.ts:208-225 (registration)Tool registration for hn_comments in ListToolsRequestSchema handler, defining name, description, and inputSchema (story_id or story_index).
{ name: "hn_comments", description: "Get comments for a story (by story ID or index from last story list)", inputSchema: { type: "object", properties: { story_id: { type: "number", description: "The ID of the story to get comments for" }, story_index: { type: "number", description: "The index (1-based) of the story from the last fetched list", minimum: 1 } } } } - index.ts:329-383 (handler)Main handler logic for hn_comments: resolves story by ID or index, fetches story details, retrieves comments via api.getComments(), formats them, and returns response.
if (name === "hn_comments") { const storyId = typeof args?.story_id === 'number' ? args.story_id : NaN; const storyIndex = typeof args?.story_index === 'number' ? args.story_index : NaN; if (isNaN(storyId) && isNaN(storyIndex)) { throw new Error('Either a story ID or a story index is required'); } let targetStoryId: number; if (!isNaN(storyId)) { targetStoryId = storyId; } else if (!isNaN(storyIndex) && storyIndex > 0 && storyIndex <= lastStoriesList.length) { targetStoryId = lastStoriesList[storyIndex - 1].id; } else { throw new Error('Invalid story index or ID provided'); } if (isNaN(targetStoryId)) { throw new Error('Story ID must be a number'); } const story = await api.getItemDetails(targetStoryId) as Story | null; if (!story) { throw new Error(`Story with ID ${targetStoryId} not found`); } if (!story.kids || story.kids.length === 0) { return { content: [ { type: "text", text: `No comments found for story "${story.title}" (ID: ${story.id})` } ] }; } const comments = await api.getComments(story.kids); const formattedComments = comments.map(comment => ({ id: comment.id, by: comment.by, time: api.formatTime(comment.time), text: api.cleanText(comment.text), replies: comment.kids ? comment.kids.length : 0 })); return { content: [ { type: "text", text: formatCommentsAsText(story.title, formattedComments) } ] }; } - index.ts:39-45 (schema)FormattedComment interface defining the output structure for comments (id, by, time, text, replies).
interface FormattedComment { id: number; by: string; time: string; text: string; replies: number; } - index.ts:20-26 (schema)Comment interface representing raw API comment data from Hacker News.
interface Comment { id: number; by: string; time: number; text: string; kids?: number[]; } - index.ts:428-443 (helper)formatCommentsAsText helper function that formats the comment list into a readable text output for the response.
function formatCommentsAsText(storyTitle: string, comments: FormattedComment[]): string { if (!comments || comments.length === 0) { return "No comments found."; } const header = `Comments for "${storyTitle}" (Total: ${comments.length}):\n`; const formattedComments = comments.map((comment, index) => { return `${index + 1}. Comment by ${comment.by} at ${comment.time}: "${comment.text}" ${comment.replies > 0 ? `(${comment.replies} replies)` : '(no replies)'} ------------------------------`; }).join('\n\n'); return header + '\n' + formattedComments; }