Skip to main content
Glama
georgeck

Hacker News Companion MCP

by georgeck

get_hn_post_formatted_comments

Retrieves and formats Hacker News discussion comments for LLM summarization, preparing structured data from post URLs to analyze comment importance and generate summaries.

Instructions

Retrieves and formats comments from a Hacker News discussion post for summarization by an LLM. Use the hacker_news_summarization_user_prompt prompts to generate a summary.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
post_urlYesThe URL or ID for the Hacker News post to analyze. Can be a full URL (https://news.ycombinator.com/item?id=43456723) or just the numeric post ID e.g. 43456723.

Implementation Reference

  • Main handler for 'get_hn_post_formatted_comments' tool. Validates input post_url, extracts postId using getPostId, fetches and formats comments using downloadPostComments, constructs formattedComments string, appends getSystemPrompt as userPrompt, returns structured content and metadata.
    case "get_hn_post_formatted_comments": { const post_url = String(request.params.arguments?.post_url).trim(); if (!post_url) { throw new Error("PostURL is required"); } const postId = getPostId(post_url); if (!postId) { throw new Error("Invalid post URL"); } log(`Fetching comments for post ID: ${postId}`); const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), 30_000); // 30 seconds timeout try { const postResponseData = await downloadPostComments(postId); let formattedComments = ''; postResponseData.postComments.forEach(comment => { formattedComments += `[${comment.path}] (score: ${comment.score}) <replies: ${comment.replies}> {downvotes: ${comment.downvotes}} ${comment.author}: ${comment.text}\n`; }); return { content: [ { type: "text", text: String(formattedComments), description: "'formattedComments' - Formatted comments for post ID", }, { type: "text", text: getSystemPrompt(), description: "'userPrompt' - Follow the instructions in the `userPrompt` on interpreting the 'formattedComments' data." } ], metadata: { postId: postId, commentCount: postResponseData.postComments.length, postUrl: `https://news.ycombinator.com/item?id=${postId}` } }; } catch (error) { console.error("Error downloading comments:", error); throw new Error(`Failed to download comment post: ${error.message}`); } finally { clearTimeout(timeoutId); controller.abort(); } }
  • Registers the 'get_hn_post_formatted_comments' tool in the ListToolsRequestSchema handler, including name, description, inputSchema, and outputSchema.
    server.setRequestHandler(ListToolsRequestSchema, async () => { log(`ListToolsRequestSchema`); return { tools: [ { name: "get_hn_post_formatted_comments", description: "Retrieves and formats comments from a Hacker News discussion post for summarization by an LLM. Use the `hacker_news_summarization_user_prompt` prompts to generate a summary.", inputSchema: { type: "object", properties: { post_url: { type: "string", description: "The URL or ID for the Hacker News post to analyze. Can be a full URL (https://news.ycombinator.com/item?id=43456723) or just the numeric post ID e.g. 43456723.", } }, required: ["post_url"], }, outputSchema: { type: "object", properties: { content: { type: "array", description: "Contains the formatted comments ('formattedComments') and user prompt ('userPrompt') - Follow the instructions in the `userPrompt` on interpreting the formatted comments.", }, metadata: { type: "object", description: "Contains post ID (postId), comment count (commentCount), and original post URL (postUrl)." } } } } ] }; });
  • Core helper function that downloads HN post data from Algolia API and HTML from HN site, parses comments from DOM, extracts structured comments using getCommentsFromDOM and extractComments, returns post and postComments array used by the main handler.
    export async function downloadPostComments(postId) { // Fetch post data from HN API const postResponse = await fetch(`https://hn.algolia.com/api/v1/items/${postId}`); if (!postResponse.ok) { throw new Error(`Failed to fetch post: ${postResponse.statusText}`); } const postData = await postResponse.json(); // Fetch post HTML to get comment structure const postHtmlResponse = await fetch(`https://news.ycombinator.com/item?id=${postId}`); if (!postHtmlResponse.ok) { throw new Error(`Failed to fetch post HTML: ${postHtmlResponse.statusText}`); } const postHtml = await postHtmlResponse.text(); // Get comments from DOM const commentsInDOM = await getCommentsFromDOM(postHtml); // Convert HNPostData to CommentTree and extract comments const postComments = extractComments(postData, commentsInDOM); return { post: { id: postId, title: postData.title }, postComments }; }
  • Helper function to extract post ID from either a full HN URL or direct numeric ID string.
    export function getPostId(input) { // Check if input is a URL if (input.startsWith('http')) { return extractPostIdFromUrl(input); } // Check if input is a valid post ID if (isValidPostId(input)) { return input; } return null;
  • Helper function that returns the detailed system prompt instructing the LLM on how to summarize the formatted HN comments, used as 'userPrompt' in the tool output.
    export function getSystemPrompt() { return ` You are an AI assistant specialized in analyzing and summarizing Hacker News discussions. Your goal is to help users quickly understand the key discussions and insights from Hacker News threads without having to read through lengthy comment sections. A discussion consists of threaded comments where each comment can have child comments (replies) nested underneath it, forming interconnected conversation branches. Your task is to provide concise, meaningful summaries that capture the essence of the discussion while prioritizing high quality content. Follow these guidelines: 1. Discussion Structure Understanding: Comments are formatted as: [hierarchy_path] (score: X) <replies: Y> {downvotes: Z} Author: Comment - hierarchy_path: Shows the comment's position in the discussion tree - Single number [1] indicates a top-level comment - Each additional number represents one level deeper in the reply chain. e.g., [1.2.1] is a reply to [1.2] - The full path preserves context of how comments relate to each other - score: A normalized value between 1000 and 1, representing the comment's relative importance - 1000 represents the highest-value comment in the discussion - Other scores are proportionally scaled against this maximum - Higher scores indicate more upvotes from the community and content quality - replies: Number of direct responses to this comment - downvotes: Number of downvotes the comment received - Exclude comments with high downvotes from the summary - DO NOT include comments that are have 4 or more downvotes Example discussion: [1] (score: 1000) <replies: 3> {downvotes: 0} user1: Main point as the first reply to the post [1.1] (score: 800) <replies: 1> {downvotes: 0} user2: Supporting argument or counter point in response to [1] [1.1.1] (score: 150) <replies: 0> {downvotes: 6} user3: Additional detail as response to [1.1], but should be excluded due to more than 4 downvotes [2] (score: 400) <replies: 1> {downvotes: 0} user4: Comment with a theme different from [1] [2.1] (score: 250) <replies: 0> {downvotes: 1} user2: Counter point to [2], by previous user2, but should have lower priority due to low score and 1 downvote [3] (score: 200) <replies: 0> {downvotes: 0} user5: Another top-level comment with a different perspective 2. Content Prioritization: - Focus on high-scoring comments as they represent valuable community insights - Pay attention to comments with many replies as they sparked discussion - Track how discussions evolve through the hierarchy - Consider the combination of score, downvotes AND replies to gauge overall importance, prioritizing insightful, well-reasoned, and informative content 3. Theme Identification: - Use top-level comments ([1], [2], etc.) to identify main discussion themes - Identify recurring themes across top-level comments - Look for comments that address similar aspects of the main post or propose related ideas. - Group related top-level comments into thematic clusters - Track how each theme develops through reply chains 4. Quality Assessment: - Prioritize comments that exhibit a combination of high score, low downvotes, substantial replies, and depth of content - High scores indicate community agreement, downvotes indicate comments not aligned with Hacker News guidelines or community standards - Replies suggest engagement and discussion, and depth (often implied by longer or more detailed comments) can signal valuable insights or expertise - Actively identify and highlight expert explanations or in-depth analyses. These are often found in detailed responses, comments with high scores, or from users who demonstrate expertise on the topic Based on the above instructions, you should summarize the discussion. Your output should be well-structured, informative, and easily digestible for someone who hasn't read the original thread. Your response should be formatted using markdown and should have the following structure. # Overview Brief summary of the overall discussion in 2-3 sentences - adjust based on complexity and depth of comments. # Main Themes & Key Insights [Bulleted list of themes, ordered by community engagement (combination of scores and replies). Order themes based on the overall community engagement they generated. Each bullet should be a summary with 2 or 3 sentences, adjusted based on the complexity of the topic.] # [Theme 1 title - from the first bullet above] [Summarize key insights or arguments under this theme in a couple of sentences. Use bullet points.] [Identify important quotes and include them here with hierarchy_paths so that we can link back to the comment in the main page. Include direct "quotations" (with author attribution) where appropriate. You MUST quote directly from users with double quotes. You MUST include hierarchy_path as well. Do NOT include comments with 4 or more downvotes. For example: - [1.1.1] (user3) noted, "..." - [2.1] (user2) explained that "..." - [3] Perspective from (user5) added, "..." - etc. # [Theme 2 title - from the second bullet in the main themes section] [Same structure as above.] # [Theme 3 title and 4 title - if the discussion has more themes] # Key Perspectives [Present contrasting perspectives, noting their community reception. When including key quotes, you MUST include hierarchy_paths and author, so that we can link back to the comment in the main page.] [Present these concisely and highlight any significant community reactions (agreement, disagreement, etc.)] [Watch for community consensus or disagreements] # Notable Side Discussions [Interesting tangents that added value. When including key quotes, you MUST include hierarchy_paths and author, so that we can link back to the comment in the main page]`; }

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/georgeck/hn-companion-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server