Endpoints: 28,729MCP servers: 18,413Payout addresses: 2,071Paid calls: 1,537Letters: 14Defects: 1,322counted 2 min ago
teppi

Server definition

Hash
sha256:906993a41bafca4e325f0aad13f583dd1518327e0d0c85d4f733dc06b2e1e984
What it is
What a remote MCP server returned when asked what it offers: 4 tools

The blob, as servednamed by its sha256

{ "instructions": "Use the hn_* tools to access Hacker News via the Firebase API and Algolia search: ranked feeds; search by keyword, by type/author/story/date/score filters alone, or both; user profiles; and items with their comment trees. Items are addressed by integer ID, reused across tools and item types (story, comment, job, poll, pollopt); passing a comment id to hn_get_thread drills into that subtree. Usernames are case-sensitive; HN sparsely populates fields, so treat absent values as unknown.", "tools": [ { "description": "Fetch stories from an HN feed (top, new, best, ask, show, jobs), with title, URL, score, author, and comment count for each story.", "inputSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "count": { "default": 30, "description": "Number of stories to return. Larger counts take longer.", "maximum": 100, "minimum": 1, "type": "integer" }, "feed": { "description": "Which HN feed to fetch. \"top\" includes jobs. \"ask\" and \"show\" are Ask HN / Show HN posts.", "enum": [ "top", "new", "best", "ask", "show", "jobs" ], "type": "string" }, "offset": { "default": 0, "description": "Number of stories to skip from the start of the feed. Use with count for pagination.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" } }, "required": [ "feed" ], "type": "object" }, "name": "hn_get_stories", "outputSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "anyOf": [ { "not": { "required": [ "error" ] }, "required": [ "stories", "feed", "total", "offset", "hasMore" ] }, { "required": [ "error" ] } ], "properties": { "cap": { "description": "The count cap that was applied.", "type": "number" }, "error": { "additionalProperties": {}, "description": "Present when the call failed. Absent on success.", "properties": { "code": { "description": "JSON-RPC error code for this failure.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "data": { "additionalProperties": {}, "properties": { "reason": { "description": "Machine-readable failure mode. Declared by this tool: `upstream_rejected`: The HN API answered with a 4xx status other than 429 — it rejected the request as built. `upstream_rate_limited`: The HN API answered with HTTP 429. `upstream_unavailable`: The HN API answered with a 5xx status. `upstream_html`: The HN API served an HTML error page with a 200 status, which it does under rate limiting or maintenance. `upstream_malformed`: The HN API answered with a 200 status and a body that is not JSON. Other values are possible when a failure originates below the handler.", "examples": [ "upstream_rejected", "upstream_rate_limited", "upstream_unavailable", "upstream_html", "upstream_malformed" ], "type": "string" }, "recovery": { "additionalProperties": {}, "description": "Actionable next step for the caller.", "properties": { "hint": { "type": "string" } }, "required": [ "hint" ], "type": "object" }, "retryable": { "description": "Whether retrying may succeed.", "type": "boolean" } }, "type": "object" }, "message": { "description": "Human-readable description of what went wrong.", "type": "string" } }, "required": [ "code", "message" ], "type": "object" }, "failedIds": { "description": "IDs on this page whose fetch failed after retries. They are not deleted or missing and may load on a later call: retry the page with the same offset, or pass an ID to hn_get_thread to fetch that story alone. Absent when every item on the page loaded.", "items": { "type": "number" }, "type": "array" }, "feed": { "description": "Which feed was fetched.", "type": "string" }, "hasMore": { "description": "Whether more stories are available beyond this page.", "type": "boolean" }, "notice": { "description": "Agent guidance: the offset to pass for the next page while more stories remain, the IDs that failed to load and how to retry them, or why a page came back empty — offset past the end of the feed, an empty feed, or every item on the page deleted or flagged. Absent on the last page of a non-empty result with no failed IDs.", "type": "string" }, "offset": { "description": "Offset that was applied to this page.", "type": "number" }, "shown": { "description": "Number of stories returned on this page.", "type": "number" }, "stories": { "description": "Stories from the feed, ordered by HN ranking.", "items": { "additionalProperties": false, "description": "A single story or job posting.", "properties": { "by": { "description": "Author username when provided by HN. Omitted when unknown.", "type": "string" }, "descendants": { "description": "Total comment count. Absent for jobs.", "type": "number" }, "domain": { "description": "Bare hostname derived from url (e.g. \"github.com\", with leading \"www.\" stripped). Absent when url is missing or unparseable.", "type": "string" }, "id": { "description": "Item ID — use with hn_get_thread to read comments.", "type": "number" }, "score": { "description": "Upvote count when provided by HN. Omitted when unknown.", "type": "number" }, "text": { "description": "Body text for Ask HN / text posts. Use hn_get_thread for full discussion.", "type": "string" }, "time": { "description": "Unix timestamp when provided by HN. Omitted when unknown.", "type": "number" }, "title": { "description": "Story title when provided by HN. Omitted when unknown.", "type": "string" }, "type": { "description": "Item type (story, job).", "type": "string" }, "url": { "description": "External link URL. Absent for Ask HN / text posts.", "type": "string" } }, "required": [ "id", "type" ], "type": "object" }, "type": "array" }, "total": { "description": "Total items in the feed (up to 500 for top/new/best, 200 for ask/show/jobs).", "type": "number" }, "truncated": { "description": "True when more stories remain beyond this page (hasMore). Absent on the last page of the feed.", "type": "boolean" } }, "type": "object" } }, { "description": "Get an item and its comment tree as a threaded discussion, with child comments resolved recursively. Use depth 0 for an item-only lookup. A long thread comes back in pages: pass the returned nextCursor as cursor to continue.", "inputSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "cursor": { "description": "nextCursor from a previous call, passed with the same itemId, to continue the traversal at the next unseen comment without repeating or skipping any. Omit to start from the top.", "type": "string" }, "depth": { "default": 3, "description": "How many levels of replies to resolve. 0 = just the item, no comments. 1 = direct replies only. Replies below this depth are never fetched — to read them, raise depth or call again with a specific comment's itemId to drill into its subtree. Ignored when cursor is set: the depth the cursor was issued with applies.", "maximum": 10, "minimum": 0, "type": "integer" }, "itemId": { "description": "ID of the story, comment, job, poll, or poll option to fetch the thread for.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "maxComments": { "default": 50, "description": "Maximum comments in one response, across all depth levels. Highest-ranked top-level comments resolve first; replies fill in only after the level above is exhausted. A response also stops at a fixed 64,000-byte text budget. When either limit stops the traversal, nextCursor continues it.", "maximum": 200, "minimum": 1, "type": "integer" } }, "required": [ "itemId" ], "type": "object" }, "name": "hn_get_thread", "outputSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "anyOf": [ { "not": { "required": [ "error" ] }, "required": [ "item", "comments", "totalLoaded" ] }, { "required": [ "error" ] } ], "properties": { "cap": { "description": "The maxComments cap that was applied.", "type": "number" }, "comments": { "description": "Flat comment list ordered breadth-first by rank: highest-ranked top-level comments first, then their replies. Use depth/parentId to reconstruct nesting. With cursor, the page continues the same order.", "items": { "additionalProperties": false, "description": "A single comment in the thread with its tree position.", "properties": { "by": { "description": "Author username.", "type": "string" }, "childCount": { "description": "Number of direct child comments (may exceed what was resolved).", "type": "number" }, "depth": { "description": "Nesting level (0 = direct reply to root).", "type": "number" }, "id": { "description": "Comment ID.", "type": "number" }, "isOp": { "const": true, "description": "Present and `true` when the comment author matches the root item author (OP replying within their own thread). Omitted otherwise — including when either author is missing. Most threads carry no OP replies, so absence is the common case; treat missing as \"not OP\" rather than unknown.", "type": "boolean" }, "parentId": { "description": "Parent item ID.", "type": "number" }, "text": { "description": "Comment text (HTML stripped).", "type": "string" }, "time": { "description": "Unix timestamp.", "type": "number" } }, "required": [ "id", "depth", "parentId", "childCount" ], "type": "object" }, "type": "array" }, "error": { "additionalProperties": {}, "description": "Present when the call failed. Absent on success.", "properties": { "code": { "description": "JSON-RPC error code for this failure.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "data": { "additionalProperties": {}, "properties": { "reason": { "description": "Machine-readable failure mode. Declared by this tool: `item_not_found`: HN reports no item exists for the given itemId. `invalid_cursor`: The cursor was issued for a different itemId than the one passed with it. `upstream_rejected`: The HN API answered with a 4xx status other than 429 — it rejected the request as built. `upstream_rate_limited`: The HN API answered with HTTP 429. `upstream_unavailable`: The HN API answered with a 5xx status. `upstream_html`: The HN API served an HTML error page with a 200 status, which it does under rate limiting or maintenance. `upstream_malformed`: The HN API answered with a 200 status and a body that is not JSON. Other values are possible when a failure originates below the handler.", "examples": [ "item_not_found", "invalid_cursor", "upstream_rejected", "upstream_rate_limited", "upstream_unavailable", "upstream_html", "upstream_malformed" ], "type": "string" }, "recovery": { "additionalProperties": {}, "description": "Actionable next step for the caller.", "properties": { "hint": { "type": "string" } }, "required": [ "hint" ], "type": "object" }, "retryable": { "description": "Whether retrying may succeed.", "type": "boolean" } }, "type": "object" }, "message": { "description": "Human-readable description of what went wrong.", "type": "string" } }, "required": [ "code", "message" ], "type": "object" }, "failedIds": { "description": "Comment and poll-option IDs whose fetch failed after retries, so neither they nor their replies are in this response. They are not deleted or missing and may load on a later call. Failed comments ride in nextCursor and are retried when you continue; without one, call again, or pass an ID as itemId to fetch that comment and its replies. Absent when everything the traversal reached loaded.", "items": { "type": "number" }, "type": "array" }, "item": { "additionalProperties": false, "description": "The root item: a story, comment, job, poll, or poll option.", "properties": { "by": { "description": "Author username.", "type": "string" }, "dead": { "const": true, "description": "Present and `true` when the root is dead (flagged or killed); its replies are still walked. Omitted otherwise.", "type": "boolean" }, "deleted": { "const": true, "description": "Present and `true` when HN reports the root deleted; its author and text are gone, but its replies are still walked. Omitted otherwise.", "type": "boolean" }, "descendants": { "description": "Total comment count.", "type": "number" }, "id": { "description": "Item ID.", "type": "number" }, "options": { "description": "For a poll root, its options with text and votes in parts order, resolved at every depth including 0. Deleted and dead options are kept and marked; an option whose fetch failed is listed in failedIds instead. Options do not count toward maxComments or totalLoaded.", "items": { "additionalProperties": false, "description": "One poll option.", "properties": { "dead": { "const": true, "description": "Present and `true` when the option is dead (flagged or killed). Omitted otherwise.", "type": "boolean" }, "deleted": { "const": true, "description": "Present and `true` when the option was deleted. Omitted otherwise.", "type": "boolean" }, "id": { "description": "Poll option ID.", "type": "number" }, "score": { "description": "Votes for this option.", "type": "number" }, "text": { "description": "Option text (HTML stripped). Absent once deleted.", "type": "string" } }, "required": [ "id" ], "type": "object" }, "type": "array" }, "parent": { "description": "For a comment root, the ID of the story or comment it replies to — pass it as itemId for the context above.", "type": "number" }, "parts": { "description": "For a poll root, its option IDs in HN order.", "items": { "type": "number" }, "type": "array" }, "poll": { "description": "For a poll-option root, the ID of its poll.", "type": "number" }, "score": { "description": "Upvote count.", "type": "number" }, "text": { "description": "Body text (HTML stripped).", "type": "string" }, "time": { "description": "Unix timestamp.", "type": "number" }, "title": { "description": "Story/job/poll title.", "type": "string" }, "type": { "description": "Item type: story | comment | job | poll | pollopt.", "type": "string" }, "url": { "description": "External link URL.", "type": "string" } }, "required": [ "id", "type" ], "type": "object" }, "nextCursor": { "description": "Pass as cursor, with the same itemId, to continue from the next unseen comment. Present when truncationReason is count, size, or rate_limited; absent on the last page.", "type": "string" }, "notice": { "description": "Traversal context: counts of deleted/dead comments dropped, the IDs that failed to load and how to retry them, then what stopped the traversal and how to continue — nextCursor for a count, size, or rate-limit stop, or a larger depth or a comment id as itemId for a depth cut. Absent when nothing was dropped, failed, or left unread.", "type": "string" }, "shown": { "description": "Number of comments returned.", "type": "number" }, "totalAvailable": { "description": "HN's total comment count for the root (descendants), which also counts dead and deleted comments. Absent for comment and job roots.", "type": "number" }, "totalLoaded": { "description": "Number of comments in this response (this page, when paging with cursor).", "type": "number" }, "truncated": { "description": "True when comments remain unread: reachable through nextCursor (truncationReason count, size, or rate_limited), or below the depth limit (depth). Absent on a terminal page — including a thread that loads in full at exactly maxComments.", "type": "boolean" }, "truncationReason": { "description": "Why the traversal stopped short: count = maxComments (or the 1,000-item ceiling per call) was reached; size = the 64,000-byte response budget was reached; rate_limited = the HN API throttled the fetches; depth = replies lie below the depth limit, which nextCursor does not reach — raise depth or pass a comment id as itemId. When a cursor reason and a depth cut both apply, the cursor reason is reported.", "enum": [ "count", "size", "depth", "rate_limited" ], "type": "string" } }, "type": "object" } }, { "description": "Get an HN user profile with karma, about, and optionally their most recent submissions resolved into full items.", "inputSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "includeSubmissions": { "default": false, "description": "Resolve the user's most recent submissions into full items. Without this, only the submission count is available.", "type": "boolean" }, "submissionCount": { "default": 10, "description": "Page size — how many submissions to resolve per call. Only used when includeSubmissions is true.", "maximum": 50, "minimum": 1, "type": "integer" }, "submissionOffset": { "default": 0, "description": "How many submissions to skip before resolving, counting back from the most recent. Use with submissionCount to page through a long history: request offset 0, then offset submissionCount, and so on. The enrichment block echoes submissionOffset and, when more remain, the offset to send next. Only used when includeSubmissions is true.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "username": { "description": "HN username. Case-sensitive. Trimmed; blank or whitespace-only input is rejected.", "minLength": 1, "type": "string" } }, "required": [ "username" ], "type": "object" }, "name": "hn_get_user", "outputSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "anyOf": [ { "not": { "required": [ "error" ] }, "required": [ "user" ] }, { "required": [ "error" ] } ], "properties": { "cap": { "description": "The submissionCount cap that was applied.", "type": "number" }, "error": { "additionalProperties": {}, "description": "Present when the call failed. Absent on success.", "properties": { "code": { "description": "JSON-RPC error code for this failure.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "data": { "additionalProperties": {}, "properties": { "reason": { "description": "Machine-readable failure mode. Declared by this tool: `user_not_found`: HN reports no user account exists for the given username. `upstream_rejected`: The HN API answered with a 4xx status other than 429 — it rejected the request as built, which a username outside HN’s charset can cause. `upstream_rate_limited`: The HN API answered with HTTP 429. `upstream_unavailable`: The HN API answered with a 5xx status. `upstream_html`: The HN API served an HTML error page with a 200 status, which it does under rate limiting or maintenance. `upstream_malformed`: The HN API answered with a 200 status and a body that is not JSON. Other values are possible when a failure originates below the handler.", "examples": [ "user_not_found", "upstream_rejected", "upstream_rate_limited", "upstream_unavailable", "upstream_html", "upstream_malformed" ], "type": "string" }, "recovery": { "additionalProperties": {}, "description": "Actionable next step for the caller.", "properties": { "hint": { "type": "string" } }, "required": [ "hint" ], "type": "object" }, "retryable": { "description": "Whether retrying may succeed.", "type": "boolean" } }, "type": "object" }, "message": { "description": "Human-readable description of what went wrong.", "type": "string" } }, "required": [ "code", "message" ], "type": "object" }, "failedIds": { "description": "Submission IDs in this window whose fetch failed after retries. They are not deleted or missing and may load on a later call: retry with the same submissionOffset, or pass an ID to hn_get_thread to fetch that item alone. Absent when every submission in the window loaded.", "items": { "type": "number" }, "type": "array" }, "notice": { "description": "Pagination context — which window of the history this page covers and the submissionOffset to send next, the submission IDs that failed to load and how to retry them, or a warning that the offset is past the end. Absent when the page reaches the end of the history with no failed IDs, or when no submissions were resolved.", "type": "string" }, "shown": { "description": "Number of submissions returned.", "type": "number" }, "submissionOffset": { "description": "The offset this page started at. Absent when includeSubmissions is false or the user has never submitted.", "type": "number" }, "submissions": { "description": "One page of submissions, most recent first, starting at submissionOffset. Absent when includeSubmissions is false or the user has never submitted. Empty when the page holds no live items — either the offset is past the end, or every item in the window was deleted, flagged, or failed to load (failedIds lists the failures).", "items": { "additionalProperties": false, "description": "A single submission by the user (story, comment, job, poll, or poll option).", "properties": { "descendants": { "description": "Comment count (stories/polls).", "type": "number" }, "id": { "description": "Item ID — use with hn_get_thread to read comments.", "type": "number" }, "parent": { "description": "For a comment, the ID of the story or comment it replied to — pass it to hn_get_thread for the context.", "type": "number" }, "poll": { "description": "For a poll option, the ID of its poll.", "type": "number" }, "score": { "description": "Score/upvotes.", "type": "number" }, "text": { "description": "Body text (HTML stripped).", "type": "string" }, "time": { "description": "Unix timestamp.", "type": "number" }, "title": { "description": "Title (stories/jobs/polls).", "type": "string" }, "type": { "description": "Item type (story, comment, job, poll, pollopt).", "type": "string" }, "url": { "description": "External link URL.", "type": "string" } }, "required": [ "id", "type" ], "type": "object" }, "type": "array" }, "truncated": { "description": "True when submissions remain beyond this page.", "type": "boolean" }, "user": { "additionalProperties": false, "description": "User profile.", "properties": { "about": { "description": "Self-description (HTML stripped).", "type": "string" }, "created": { "description": "Account creation time (Unix timestamp).", "type": "number" }, "id": { "description": "Username.", "type": "string" }, "karma": { "description": "Karma score.", "type": "number" }, "totalSubmissions": { "description": "Total number of submissions.", "type": "number" } }, "required": [ "id", "karma", "created", "totalSubmissions" ], "type": "object" } }, "type": "object" } }, { "description": "Search Hacker News stories, comments, polls, and jobs via Algolia — by keyword, by filters alone, or both. Filterable by content type, author, parent story, date range, and minimum points.", "inputSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "properties": { "author": { "description": "Filter results to a specific author. Useful for finding a user's posts on a topic (hn_get_user only shows recent submissions). Trimmed before filtering; omit the field to search all authors rather than passing a blank string.", "minLength": 1, "type": "string" }, "count": { "default": 30, "description": "Number of results to return.", "maximum": 50, "minimum": 1, "type": "integer" }, "dateRange": { "description": "Filter to a creation-time window with a start, an end, or both. An empty object is rejected — omit dateRange instead.", "properties": { "end": { "description": "Exclusive upper bound — only items created strictly before this instant match. Same formats and UTC reading as start, and must be later than start. A date-only end excludes that whole UTC day: to include it, pass the next day or a full timestamp.", "pattern": "^(\\d{4})(?:-(\\d{2})(?:-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d{1,3})?)?(?:Z|[+-](\\d{2}):(\\d{2}))?)?)?)?$", "type": "string" }, "start": { "description": "Exclusive lower bound — only items created strictly after this instant match. ISO 8601: YYYY, YYYY-MM, YYYY-MM-DD, or YYYY-MM-DDThh:mm[:ss[.sss]] with an optional Z or ±hh:mm offset. Reduced and date-only forms mean UTC midnight at the start of that period; a date-time without an offset is read as UTC.", "pattern": "^(\\d{4})(?:-(\\d{2})(?:-(\\d{2})(?:T(\\d{2}):(\\d{2})(?::(\\d{2})(?:\\.\\d{1,3})?)?(?:Z|[+-](\\d{2}):(\\d{2}))?)?)?)?$", "type": "string" } }, "type": "object" }, "minPoints": { "description": "Minimum score. Applies to stories and polls, including the ask_hn, show_hn, and front_page subsets. Comments and jobs carry no points in the search index, so any minPoints excludes them — combining it with tags \"comment\" or \"job\" is rejected.", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "page": { "default": 0, "description": "Page number for pagination (0-indexed).", "maximum": 9007199254740991, "minimum": 0, "type": "integer" }, "query": { "description": "Search terms. Supports simple keywords — Algolia handles stemming and relevance. Trimmed before searching; blank or whitespace-only input is rejected. Omit for a filter-only search, which needs at least one of tags, author, storyId, minPoints, or a dateRange bound.", "minLength": 1, "type": "string" }, "sort": { "default": "relevance", "description": "Sort order. \"relevance\" for best match, \"date\" for most recent first.", "enum": [ "relevance", "date" ], "type": "string" }, "storyId": { "description": "Restrict results to one discussion: the id of a story or poll root, combined with the other filters. Pair with tags \"comment\" to search within a thread. Take it from hits[].storyId or the root item of hn_get_thread — a comment id matches nothing.", "exclusiveMinimum": 0, "maximum": 9007199254740991, "type": "integer" }, "tags": { "description": "Filter results by content type: \"story\", \"comment\", \"poll\", or \"job\", or the story subsets \"ask_hn\", \"show_hn\", and \"front_page\". Omit to search all types.", "enum": [ "story", "comment", "poll", "job", "ask_hn", "show_hn", "front_page" ], "type": "string" }, "view": { "default": "full", "description": "How much of each hit to return. \"full\" includes every field. \"compact\" omits the two body-text fields — `text` and `highlights.text` — which together can repeat a long comment twice per hit; everything else (id, title, url, domain, author, points, comment count, timestamp, parent story, title highlight, matchedWords) is unchanged. Use \"compact\" to scan many results, then pass a hit id to hn_get_thread to read the body you skipped.", "enum": [ "full", "compact" ], "type": "string" } }, "type": "object" }, "name": "hn_search_content", "outputSchema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "additionalProperties": false, "anyOf": [ { "not": { "required": [ "error" ] }, "required": [ "hits", "totalHits", "page", "totalPages" ] }, { "required": [ "error" ] } ], "properties": { "cap": { "description": "The count cap that was applied.", "type": "number" }, "error": { "additionalProperties": {}, "description": "Present when the call failed. Absent on success.", "properties": { "code": { "description": "JSON-RPC error code for this failure.", "maximum": 9007199254740991, "minimum": -9007199254740991, "type": "integer" }, "data": { "additionalProperties": {}, "properties": { "reason": { "description": "Machine-readable failure mode. Declared by this tool: `missing_query_or_filter`: Neither a query nor any filter was supplied, so there is nothing to search by. `invalid_date_range`: dateRange was supplied with neither bound, or with start not before end. `min_points_unscored_type`: minPoints was combined with tags \"comment\" or \"job\", record types Algolia stores without points. `upstream_rejected`: Algolia answered with a 4xx status other than 429 — it rejected the request as built. `upstream_rate_limited`: Algolia answered with HTTP 429. `upstream_unavailable`: Algolia answered with a 5xx status. `upstream_html`: Algolia served an HTML error page with a 200 status, which it does under rate limiting or maintenance. `upstream_malformed`: Algolia answered with a 200 status and a body that is not JSON. Other values are possible when a failure originates below the handler.", "examples": [ "missing_query_or_filter", "invalid_date_range", "min_points_unscored_type", "upstream_rejected", "upstream_rate_limited", "upstream_unavailable", "upstream_html", "upstream_malformed" ], "type": "string" }, "recovery": { "additionalProperties": {}, "description": "Actionable next step for the caller.", "properties": { "hint": { "type": "string" } }, "required": [ "hint" ], "type": "object" }, "retryable": { "description": "Whether retrying may succeed.", "type": "boolean" } }, "type": "object" }, "message": { "description": "Human-readable description of what went wrong.", "type": "string" } }, "required": [ "code", "message" ], "type": "object" }, "hits": { "description": "Search results ranked by sort order.", "items": { "additionalProperties": false, "description": "A single Algolia search hit (story, comment, poll, or job).", "properties": { "author": { "description": "Author username.", "type": "string" }, "createdAt": { "description": "Creation time (ISO 8601).", "type": "string" }, "domain": { "description": "Bare hostname derived from url (e.g. \"github.com\", with leading \"www.\" stripped). Absent when url is missing or unparseable.", "type": "string" }, "highlights": { "additionalProperties": false, "description": "Algolia per-field highlight metadata showing which terms matched and where. Absent when no fields produced a match.", "properties": { "matchedWords": { "description": "Deduplicated union of matched terms across all searchable fields (title, url, author, comment_text, story_text, story_title).", "items": { "type": "string" }, "type": "array" }, "text": { "description": "Body snippet (comment_text or story_text), HTML stripped, with matched terms wrapped in `<em>…</em>`. A literal `<em>` typed into the body is indistinguishable from a marker. Absent when the body did not match, and always absent under view \"compact\" — matchedWords still lists what matched.", "type": "string" }, "title": { "description": "Title snippet with matched terms wrapped in `<em>…</em>`. Titles are not HTML, though some arrive entity-encoded; entities are decoded and no tags are stripped, so a literal `<em>` in the title is indistinguishable from a marker. Absent when the title did not match.", "type": "string" } }, "required": [ "matchedWords" ], "type": "object" }, "id": { "description": "HN item ID — use with hn_get_thread to read the discussion.", "type": "number" }, "numComments": { "description": "Comment count.", "type": "number" }, "points": { "description": "Score/upvotes.", "type": "number" }, "storyId": { "description": "Parent story ID for comment hits; equals `id` for story hits.", "type": "number" }, "storyTitle": { "description": "Parent story title (present for comment results).", "type": "string" }, "text": { "description": "Comment or story body text (HTML stripped). Absent when the hit has no body, and always absent under view \"compact\" — call hn_get_thread with this id to read it.", "type": "string" }, "title": { "description": "Item title (present for stories, polls, and jobs).", "type": "string" }, "url": { "description": "External link URL.", "type": "string" } }, "required": [ "id", "author", "createdAt" ], "type": "object" }, "type": "array" }, "notice": { "description": "Agent guidance: the next page to request while more pages remain, the last valid page when the requested page is past the end, or the filters to relax when a first page comes back empty. Absent on the last page of a non-empty result.", "type": "string" }, "page": { "description": "Current page number (0-indexed).", "type": "number" }, "query": { "description": "The query that was searched. Absent for a filter-only search.", "type": "string" }, "shown": { "description": "Number of hits returned.", "type": "number" }, "totalHits": { "description": "Total matching results across all pages.", "type": "number" }, "totalPages": { "description": "Number of pages Algolia will actually serve for this query. Not derived from totalHits — broad queries report a totalHits far larger than the reachable page range, so paginate against this value.", "type": "number" }, "truncated": { "description": "True when more pages remain after this one (page + 1 < totalPages). Absent on the last page Algolia serves.", "type": "boolean" } }, "type": "object" } } ] }
Verify it yourselfcurl -s https://api.teppi.xyz/v1/evidence/sha256:906993a41bafca4e325f0aad13f583dd1518327e0d0c85d4f733dc06b2e1e984 | sha256sum