Skip to main content
Glama

search-posts

Search HackerNews content by keyword with filters for tags, points, comments, and dates to find relevant stories and discussions.

Instructions

Search HackerNews for stories, comments, and other content by keyword.

Supports:

  • Keyword search across titles, text, and authors

  • Tag filtering (story, comment, poll, show_hn, ask_hn, front_page, author_USERNAME)

  • Numeric filters for points, comments, and dates

  • Pagination with customizable results per page

  • Advanced filtering with OR logic and multiple conditions

Basic Examples:

  • Search for AI stories: { "query": "AI", "tags": ["story"] }

  • Find popular posts: { "query": "Python", "numericFilters": ["points>=100"] }

  • Filter by author: { "query": "startup", "tags": ["author_pg"] }

  • Date range: { "query": "startup", "numericFilters": ["created_at_i>1640000000"] }

Advanced Filtering Examples:

  • High engagement posts: { "query": "programming", "numericFilters": ["points>=100", "num_comments>=50"] }

  • OR logic for tags: { "query": "web", "tags": ["(story,poll)"] } - returns stories OR polls

  • Author with filters: { "query": "", "tags": ["author_pg", "story"], "numericFilters": ["points>=50"] }

  • Multiple conditions: { "query": "AI", "tags": ["story"], "numericFilters": ["points>=200", "num_comments>=100"] }

Numeric Filter Operators: < (less than), <= (less than or equal), = (equal), >= (greater than or equal), > (greater than) Numeric Filter Fields: points, num_comments, created_at_i (Unix timestamp)

Tag Syntax:

  • Single tag: ["story"] - only stories

  • Multiple tags (AND): ["story", "show_hn"] - stories that are also show_hn

  • OR logic: ["(story,poll)"] - stories OR polls

  • Author filter: ["author_USERNAME"] - posts by specific author

Returns paginated results with hits, total count, and page information.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYes
tagsNo
numericFiltersNo
pageNo
hitsPerPageNo

Implementation Reference

  • Core handler logic for all tools including 'search-posts': forwards arguments to remote API https://mcp.xiaobenyang.com/api using toolName='search-posts' in headers, returns text response as MCP content.
    const calcXiaoBenYangApi = async function (fullArgs: Record<string, any>) { // 发起 POST 请求 let response = await fetch('https://mcp.xiaobenyang.com/api', { method: 'POST', headers: { 'XBY-APIKEY': apiKey, 'func': fullArgs.toolName, 'mcpid': mcpID }, body: new URLSearchParams(fullArgs) }); const apiResult = await response.text(); return { content: [ { type: "text", text: apiResult // 将字符串结果放入 content 中 } ] } as { [x: string]: unknown; content: [{ type: "text"; text: string }] }; };
  • Intermediate handler called by registered tool handler: adds toolName to args and invokes the API proxy.
    const handleXiaoBenYangApi = async (args: Record<string, any>, toolName: string) => { // 校验aid是否存在 if (toolName === undefined || toolName === null) { throw new Error("缺少必要参数 'aid'"); } // 合并参数 const fullArgs = {...args, toolName: toolName}; // 调用API return calcXiaoBenYangApi(fullArgs); };
  • src/mcp.ts:50-65 (registration)
    Helper function that registers each tool (including 'search-posts') with dynamic schema, description, and shared handler.
    const addToolXiaoBenYangApi = function ( name: string, desc: string, params: Record<string, ZodType> ) { server.registerTool( name, { title: name, description: desc, inputSchema: params, } , async (args: Record<string, any>) => handleXiaoBenYangApi(args, name) ) };
  • src/mcp.ts:88-132 (registration)
    Dynamically fetches tool definitions from remote (https://mcp.xiaobenyang.com/getMcpDesc?mcpId=1777316659382275) and registers them, including 'search-posts', with generated Zod schemas.
    const apiDescList = data.tools; for (const apiDesc of apiDescList) { let inputSchema = JSON.parse(apiDesc.inputSchema); const zodDict: Record<string, z.ZodTypeAny> = {}; Object.entries(inputSchema.properties).forEach(([name, propConfig]) => { let zodType; let pt = (propConfig as { type: string }).type; switch (pt) { case 'string': zodType = z.string(); break; case 'number': zodType = z.number(); break; case 'boolean': zodType = z.boolean(); break; case 'integer': zodType = z.int32(); break; case 'array': zodType = z.array(z.any()); break; case 'object': zodType = z.object(z.any()); break; default: zodType = z.any(); } if (inputSchema.required?.includes(name)) { zodDict[name] = zodType; } else { zodDict[name] = zodType.optional(); } }); addToolXiaoBenYangApi( apiDesc.name, apiDesc.description ? apiDesc.description : apiDesc.name, zodDict); }
  • Generates Zod input schema for each tool based on remote JSON schema description, mapping types to Zod types and handling required/optional.
    let inputSchema = JSON.parse(apiDesc.inputSchema); const zodDict: Record<string, z.ZodTypeAny> = {}; Object.entries(inputSchema.properties).forEach(([name, propConfig]) => { let zodType; let pt = (propConfig as { type: string }).type; switch (pt) { case 'string': zodType = z.string(); break; case 'number': zodType = z.number(); break; case 'boolean': zodType = z.boolean(); break; case 'integer': zodType = z.int32(); break; case 'array': zodType = z.array(z.any()); break; case 'object': zodType = z.object(z.any()); break; default: zodType = z.any(); } if (inputSchema.required?.includes(name)) { zodDict[name] = zodType; } else { zodDict[name] = zodType.optional(); } });

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/xiaobenyang-com/HackerNews-Search'

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