@cyanheads/hn-mcp-server 0.5.21 → 0.5.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +7 -4
- package/CLAUDE.md +7 -4
- package/Dockerfile +4 -4
- package/README.md +17 -12
- package/changelog/0.5.x/0.5.22.md +45 -0
- package/dist/mcp-server/tools/definitions/get-stories.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-stories.tool.js +23 -12
- package/dist/mcp-server/tools/definitions/get-stories.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-thread.tool.d.ts +3 -2
- package/dist/mcp-server/tools/definitions/get-thread.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-thread.tool.js +192 -99
- package/dist/mcp-server/tools/definitions/get-thread.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-user.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-user.tool.js +22 -8
- package/dist/mcp-server/tools/definitions/get-user.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/search-content.tool.d.ts +93 -0
- package/dist/mcp-server/tools/definitions/search-content.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-content.tool.js +322 -59
- package/dist/mcp-server/tools/definitions/search-content.tool.js.map +1 -1
- package/dist/mcp-server/tools/served-at-cap.d.ts +14 -0
- package/dist/mcp-server/tools/served-at-cap.d.ts.map +1 -0
- package/dist/mcp-server/tools/served-at-cap.js +16 -0
- package/dist/mcp-server/tools/served-at-cap.js.map +1 -0
- package/dist/mcp-server/tools/thread-cursor.d.ts +68 -0
- package/dist/mcp-server/tools/thread-cursor.d.ts.map +1 -0
- package/dist/mcp-server/tools/thread-cursor.js +200 -0
- package/dist/mcp-server/tools/thread-cursor.js.map +1 -0
- package/dist/services/hn/hn-service.d.ts +29 -4
- package/dist/services/hn/hn-service.d.ts.map +1 -1
- package/dist/services/hn/hn-service.js +58 -25
- package/dist/services/hn/hn-service.js.map +1 -1
- package/dist/services/hn/types.d.ts +9 -0
- package/dist/services/hn/types.d.ts.map +1 -1
- package/package.json +9 -9
- package/server.json +3 -3
package/AGENTS.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** hn-mcp-server
|
|
4
|
-
**Version:** 0.5.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.
|
|
4
|
+
**Version:** 0.5.22
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.15`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
|
-
**MCP SDK:** `@modelcontextprotocol/server` 2.
|
|
8
|
-
**Zod:** ^4.6.
|
|
7
|
+
**MCP SDK:** `@modelcontextprotocol/server` 2.3.1
|
|
8
|
+
**Zod:** ^4.6.7
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
11
11
|
|
|
@@ -218,6 +218,8 @@ src/
|
|
|
218
218
|
types.ts # HN domain types
|
|
219
219
|
mcp-server/
|
|
220
220
|
tools/markdown-escape.ts # format() boundary: escape titles, quote bodies
|
|
221
|
+
tools/served-at-cap.ts # notice sentence for a size input served at its per-call cap
|
|
222
|
+
tools/thread-cursor.ts # hn_get_thread cursor codec: packed frontier, JSON format still decoded
|
|
221
223
|
tools/definitions/
|
|
222
224
|
get-stories.tool.ts # hn_get_stories — Fetch stories from an HN feed
|
|
223
225
|
get-thread.tool.ts # hn_get_thread — Get item + comment tree
|
|
@@ -378,6 +380,7 @@ import { getHnService } from '@/services/hn/hn-service.js';
|
|
|
378
380
|
bun publish --access public
|
|
379
381
|
|
|
380
382
|
docker buildx build --platform linux/amd64,linux/arm64 \
|
|
383
|
+
--build-arg APP_VERSION=<version> \
|
|
381
384
|
-t ghcr.io/cyanheads/hn-mcp-server:<version> \
|
|
382
385
|
-t ghcr.io/cyanheads/hn-mcp-server:latest \
|
|
383
386
|
--push .
|
package/CLAUDE.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** hn-mcp-server
|
|
4
|
-
**Version:** 0.5.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.
|
|
4
|
+
**Version:** 0.5.22
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.15`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
|
-
**MCP SDK:** `@modelcontextprotocol/server` 2.
|
|
8
|
-
**Zod:** ^4.6.
|
|
7
|
+
**MCP SDK:** `@modelcontextprotocol/server` 2.3.1
|
|
8
|
+
**Zod:** ^4.6.7
|
|
9
9
|
|
|
10
10
|
> **Read the framework docs first:** `node_modules/@cyanheads/mcp-ts-core/CLAUDE.md` contains the full API reference — builders, Context, error codes, exports, patterns. This file covers server-specific conventions only.
|
|
11
11
|
|
|
@@ -218,6 +218,8 @@ src/
|
|
|
218
218
|
types.ts # HN domain types
|
|
219
219
|
mcp-server/
|
|
220
220
|
tools/markdown-escape.ts # format() boundary: escape titles, quote bodies
|
|
221
|
+
tools/served-at-cap.ts # notice sentence for a size input served at its per-call cap
|
|
222
|
+
tools/thread-cursor.ts # hn_get_thread cursor codec: packed frontier, JSON format still decoded
|
|
221
223
|
tools/definitions/
|
|
222
224
|
get-stories.tool.ts # hn_get_stories — Fetch stories from an HN feed
|
|
223
225
|
get-thread.tool.ts # hn_get_thread — Get item + comment tree
|
|
@@ -378,6 +380,7 @@ import { getHnService } from '@/services/hn/hn-service.js';
|
|
|
378
380
|
bun publish --access public
|
|
379
381
|
|
|
380
382
|
docker buildx build --platform linux/amd64,linux/arm64 \
|
|
383
|
+
--build-arg APP_VERSION=<version> \
|
|
381
384
|
-t ghcr.io/cyanheads/hn-mcp-server:<version> \
|
|
382
385
|
-t ghcr.io/cyanheads/hn-mcp-server:latest \
|
|
383
386
|
--push .
|
package/Dockerfile
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
# output. A stage that compiles a native addon needs the target-arch toolchain
|
|
15
15
|
# and cannot cross-compile this way — drop the flag there.
|
|
16
16
|
# ==============================================================================
|
|
17
|
-
FROM --platform=$BUILDPLATFORM oven/bun:1.4.
|
|
17
|
+
FROM --platform=$BUILDPLATFORM oven/bun:1.4.3 AS build
|
|
18
18
|
|
|
19
19
|
WORKDIR /usr/src/app
|
|
20
20
|
|
|
@@ -46,7 +46,7 @@ RUN bun run build
|
|
|
46
46
|
# A clean image rather than `FROM build`: the build stage's node_modules holds
|
|
47
47
|
# devDependencies.
|
|
48
48
|
# ==============================================================================
|
|
49
|
-
FROM --platform=$BUILDPLATFORM oven/bun:1.4.
|
|
49
|
+
FROM --platform=$BUILDPLATFORM oven/bun:1.4.3 AS deps
|
|
50
50
|
|
|
51
51
|
WORKDIR /usr/src/app
|
|
52
52
|
|
|
@@ -114,7 +114,7 @@ RUN rm -rf node_modules/@socketsecurity/bun-security-scanner
|
|
|
114
114
|
# dependencies and build artifacts. Its only Bun invocations are HEALTHCHECK
|
|
115
115
|
# and CMD, which run on the real target at container start.
|
|
116
116
|
# ==============================================================================
|
|
117
|
-
FROM oven/bun:1.4.
|
|
117
|
+
FROM oven/bun:1.4.3-slim AS production
|
|
118
118
|
|
|
119
119
|
WORKDIR /usr/src/app
|
|
120
120
|
|
|
@@ -124,7 +124,7 @@ ENV NODE_ENV=production
|
|
|
124
124
|
# OCI image metadata (https://github.com/opencontainers/image-spec/blob/main/annotations.md)
|
|
125
125
|
ARG APP_VERSION
|
|
126
126
|
LABEL org.opencontainers.image.title="hn-mcp-server"
|
|
127
|
-
LABEL org.opencontainers.image.description="MCP server for Hacker News
|
|
127
|
+
LABEL org.opencontainers.image.description="MCP server for Hacker News: feeds, threads, users, and search via Firebase and Algolia APIs"
|
|
128
128
|
LABEL org.opencontainers.image.source="https://github.com/cyanheads/hn-mcp-server"
|
|
129
129
|
LABEL org.opencontainers.image.licenses="Apache-2.0"
|
|
130
130
|
LABEL org.opencontainers.image.version="${APP_VERSION}"
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/hn-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/hn-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
|
|
30
30
|
## Overview
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Hacker News feeds, threads, and profiles. Browse ranked feeds, read full comment threads, look up users, and search stories, comments, polls, and jobs by keyword, author, date, or score.
|
|
33
33
|
|
|
34
34
|
### Tools
|
|
35
35
|
|
|
@@ -44,7 +44,7 @@ Feeds, threads, and profiles from the Hacker News Firebase API and Algolia Searc
|
|
|
44
44
|
|
|
45
45
|
### `hn_get_stories` <sub>tool</sub>
|
|
46
46
|
|
|
47
|
-
- Six feed types: `top`, `new`, `best`, `ask`, `show`, `jobs`; `count` (
|
|
47
|
+
- Six feed types: `top`, `new`, `best`, `ask`, `show`, `jobs`; `count` (default 30) and `offset` for pagination. One call serves at most 100 stories; a `count` up to 1,000 is served at 100, with a `notice` naming the next `offset`
|
|
48
48
|
- Returns id, type, title, url, domain, score, author, timestamp, comment count, and body text — each field omitted (not null) when HN doesn't provide it
|
|
49
49
|
- Enrichment reports `total`, `offset`, and `hasMore`; while more stories remain, `truncated` is set and `notice` names the next `offset`, and a `notice` explains empty pages (empty feed, offset past end, or every item on the page deleted/flagged). The last page carries no truncation
|
|
50
50
|
- Items whose fetch failed after retries are listed in `failedIds` with a `notice` naming the retry; a page where every item failed returns the classified upstream error instead of an empty list
|
|
@@ -53,19 +53,19 @@ Feeds, threads, and profiles from the Hacker News Firebase API and Algolia Searc
|
|
|
53
53
|
|
|
54
54
|
### `hn_get_thread` <sub>tool</sub>
|
|
55
55
|
|
|
56
|
-
- `itemId` plus `depth` (
|
|
56
|
+
- `itemId` plus `depth` (default 3; 0 returns the item with no comments) and `maxComments` (default 50) capping one response across all levels, alongside a fixed 64,000-byte text budget that cuts only between comments. One call resolves at most 10 levels and 200 comments; a `depth` up to 100 is served at 10 and a `maxComments` up to 1,000 at 200, with a `notice` naming the comment to pass as `itemId` or the `nextCursor` that reaches the rest
|
|
57
57
|
- Breadth-first traversal ranked like HN — top-ranked top-level comments resolve first, replies fill in only after the level above is exhausted
|
|
58
|
-
- Resumable: a response stopped by `maxComments`, the byte budget, or an upstream rate limit returns `nextCursor`; passing it back as `cursor` with the same `itemId` continues at the next unseen comment. The cursor carries the unvisited comments themselves, so re-ranked replies cannot shift it, and the server keeps no session state. A cursor passed with a different `itemId` fails with `invalid_cursor`
|
|
59
|
-
- The root carries its relationships and state: `parent` for a comment, `poll` for a poll option, `parts` and resolved `options` (text and votes, at every depth) for a poll, and `deleted`/`dead` markers. The `content[]` heading names the type — a title, `Comment by <author>`, `Poll option by <author> on poll <id>` — and marks a deleted or dead root
|
|
60
|
-
- Flat comment list carries `depth`/`parentId` for tree reconstruction, plus `childCount` and an `isOp` flag when the comment author
|
|
61
|
-
- `truncated` and `truncationReason` (`count`, `size`, `rate_limited`, or `depth` when replies lie below the depth limit) are set only while comments remain unread — never on a terminal page, including a thread that loads in full at exactly the cap. `notice` reports deleted/dead comments omitted during traversal and the next step: the cursor, or a larger `depth` or a comment id as `itemId
|
|
58
|
+
- Resumable: a response stopped by `maxComments`, the byte budget, or an upstream rate limit returns `nextCursor`; passing it back as `cursor` with the same `itemId` continues at the next unseen comment. The cursor carries the unvisited comments themselves, so re-ranked replies cannot shift it, and the server keeps no session state. A cursor the tool did not issue, an altered one, or one passed with a different `itemId` fails with `invalid_cursor`
|
|
59
|
+
- The root carries its relationships and state: `parent` and `storyId` (the story or poll the discussion belongs to) for a comment, `poll` for a poll option, `parts` and resolved `options` (text and votes, at every depth) for a poll, and `deleted`/`dead` markers. The `content[]` heading names the type — a title, `Comment by <author>`, `Poll option by <author> on poll <id>` — and marks a deleted or dead root
|
|
60
|
+
- Flat comment list carries `depth`/`parentId` for tree reconstruction, plus `childCount` and an `isOp` flag when the comment author submitted the thread's story — on a comment root, the story at `storyId`, never the comment's own author. Dead and deleted comments are left out, but their live replies are still returned at their true `depth`, with `parentId` naming the omitted comment
|
|
61
|
+
- `truncated` and `truncationReason` (`count`, `size`, `rate_limited`, or `depth` when replies lie below the depth limit) are set only while comments remain unread — never on a terminal page, including a thread that loads in full at exactly the cap. `notice` reports deleted/dead comments omitted during traversal and the next step: the cursor, or a larger `depth` or a comment id as `itemId`, naming by ID any omitted comment whose replies the depth limit cut
|
|
62
62
|
- Comments and poll options whose fetch failed after retries are listed in `failedIds`, and `notice` names them with the retry; failed comments ride in `nextCursor`, so paging on retries them rather than skipping them. The root item is still returned, and a failure is never passed off as a `maxComments`/`depth` limit
|
|
63
63
|
|
|
64
64
|
---
|
|
65
65
|
|
|
66
66
|
### `hn_get_user` <sub>tool</sub>
|
|
67
67
|
|
|
68
|
-
- `username` is case-sensitive and trimmed; `includeSubmissions` (default false) resolves recent submissions, with `submissionCount` (
|
|
68
|
+
- `username` is case-sensitive and trimmed; `includeSubmissions` (default false) resolves recent submissions, with `submissionCount` (default 10) and `submissionOffset` paging through a long history. One call resolves at most 50 submissions; a `submissionCount` up to 1,000 is served at 50, with a `notice` naming the next `submissionOffset`
|
|
69
69
|
- Profile includes karma, creation date, and about text (HTML stripped); submissions filter out dead/deleted items
|
|
70
70
|
- A comment submission carries its `parent` and a poll-option submission its `poll`, so either links back to what it answered
|
|
71
71
|
- Enrichment echoes `submissionOffset` and the offset to send next, or a notice when the requested offset is past the end of the history
|
|
@@ -75,13 +75,18 @@ Feeds, threads, and profiles from the Hacker News Firebase API and Algolia Searc
|
|
|
75
75
|
|
|
76
76
|
### `hn_search_content` <sub>tool</sub>
|
|
77
77
|
|
|
78
|
-
- Free-text `query` plus `tags` (`story`/`comment`/`poll`/`job`/`ask_hn`/`show_hn`/`front_page`), `author
|
|
78
|
+
- Free-text `query` plus `tags` (`story`/`comment`/`poll`/`job`/`ask_hn`/`show_hn`/`front_page`), `author` (the exact, case-sensitive username), `storyId`, `dateRange`, and `minPoints` filters; `sort` by relevance or date; `count` (default 30) and `page` for pagination. One call serves at most 50 hits; a `count` up to 1,000 is served as the page of 50 starting at the requested page's first hit, with a `notice` naming the `count: 50` page to pass next; a non-zero `page` whose first hit begins no page of 50 fails with `count_page_unaligned`, naming a `count` and `page` that start there and, when that count is under 25, the page of 50 that holds that hit
|
|
79
|
+
- `tags: "front_page"` is the front page right now (about 30 stories), never past front pages; for an earlier window, use `tags: "story"` with `dateRange` and `minPoints`
|
|
79
80
|
- `query` is optional when a filter is set — list Ask HN, Show HN, polls, or jobs on their own, or pass a story's `storyId` with `tags: "comment"` to search within one thread. No query and no filter fails with `missing_query_or_filter`
|
|
81
|
+
- To check whether a page was discussed, pass its URL alone as `query`: the leading `http://`, `https://`, or `www.` is dropped before searching, so submissions under either scheme, with or without `www.`, all match. The output `query` and the notice show what was searched
|
|
80
82
|
- `dateRange` bounds take ISO 8601 (`YYYY`, `YYYY-MM`, `YYYY-MM-DD`, or a date-time with optional offset), read as UTC and both exclusive; an empty or out-of-order range fails with `invalid_date_range`
|
|
81
83
|
- `minPoints` applies to stories and polls — comments and jobs carry no points, so pairing it with `tags: "comment"` or `"job"` fails with `min_points_unscored_type`
|
|
82
84
|
- `view: "compact"` drops the two body-text fields (`text`, `highlights.text`), which otherwise repeat a long comment twice per hit — pass a hit id to `hn_get_thread` to read the body
|
|
85
|
+
- Each hit carries its `type` (`story`, `comment`, `poll`, `pollopt`, `job`) when Algolia records one. Untagged searches also return poll options, which carry only an id, author, vote count, and date — `hn_get_thread` reads an option's text and poll. A poll hit has no `storyId`; its own `id` is the discussion root
|
|
86
|
+
- Job descriptions come back as `text`, though keywords don't search them
|
|
83
87
|
- Highlight metadata (`highlights.title`, `highlights.text`, `matchedWords`) shows which terms matched and where
|
|
84
|
-
- Enrichment
|
|
88
|
+
- Enrichment echoes the applied `criteria` — each filter set (`author` trimmed, `dateRange` as the exclusive UTC bounds applied, to the second), plus `sort`, `count`, and `view` with defaults filled — so a saved result says what it answers
|
|
89
|
+
- Enrichment reports `totalHits`, `page`, and the actual reachable `totalPages` — not derived from `totalHits`, since broad queries report far more hits than Algolia will serve. `totalHitsExact: false` marks `totalHits` as an estimate, and `reachableHits: 1000` marks a search that matches more than Algolia's 1,000-hit ceiling; the last page of such a search gets a notice naming the ceiling and narrower `dateRange` windows to reach the rest. While more pages remain, `truncated` is set and `notice` names the next `page`; a page past the end gets a notice naming the last valid page (or `page: 0` past the ceiling)
|
|
85
90
|
|
|
86
91
|
## Features
|
|
87
92
|
|
|
@@ -99,7 +104,7 @@ Agent-friendly output:
|
|
|
99
104
|
|
|
100
105
|
- Graceful partial failure — an item whose fetch fails after retries is reported by ID in `failedIds`, apart from deleted, dead, or nonexistent items, rather than silently shrinking the result; `hn_get_thread` also counts the deleted and dead comments it drops, and a rate-limited item stops the batch instead of sending every remaining item through its own retry ladder
|
|
101
106
|
- Discriminated output contracts — typed error reasons (`item_not_found`, `upstream_rate_limited`, `upstream_html`, …) with per-reason recovery text (a rate limit passes on the upstream's `Retry-After` as `retryAfter`), and a `depth`/`parentId` pair on every comment so callers reconstruct the tree without guessing nesting
|
|
102
|
-
- Pagination provenance — every paged listing echoes the offset it used (`offset`, `submissionOffset`, `page`) plus the exact next-offset value in `notice`, and `hn_get_thread` returns a self-contained `nextCursor`, so an agent can resume without recomputing state
|
|
107
|
+
- Pagination provenance — every paged listing echoes the offset it used (`offset`, `submissionOffset`, `page`) plus the exact next-offset value in `notice`, `hn_search_content` also echoes the `criteria` it searched with, and `hn_get_thread` returns a self-contained `nextCursor`, so an agent can resume without recomputing state
|
|
103
108
|
- Response shaping — HTML stripping, URL normalization, and domain extraction remove upstream markup noise; `hn_search_content`'s `view: "compact"` drops the two body-text fields that otherwise duplicate a hit's full text
|
|
104
109
|
- Fenced upstream text — in `content[]`, every line of a body is block-quoted and titles are escaped only where they could break the surrounding Markdown, so a comment cannot pass for a server-authored line
|
|
105
110
|
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "hn_get_thread returns live replies below dead and deleted comments, marks OP against the story's author on comment roots, and issues packed cursors; hn_search_content discloses estimated totals, echoes its criteria, and types its hits; an over-cap count is served at the cap."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.5.22 — 2026-10-18
|
|
8
|
+
|
|
9
|
+
## Changed
|
|
10
|
+
|
|
11
|
+
- **`hn_get_thread` adds `item.storyId`**: a comment root names the story or poll its discussion belongs to, rendered as `story:<id>` in `content[]`. Absent when the story could not be found; `notice` says why. (#42)
|
|
12
|
+
- **`hn_search_content` adds `criteria`**: the applied filters plus `sort`, `count`, and `view` with defaults filled, `author` trimmed and `dateRange` as the exclusive UTC bounds sent, echoed in `structuredContent` and as a `**criteria:**` line in `content[]`. (#35)
|
|
13
|
+
- **`hn_search_content` adds `totalHitsExact` and `reachableHits`**: `totalHitsExact: false` marks `totalHits` as an estimate, and `reachableHits: 1000` marks a search matching more than Algolia serves; the last reachable page's `notice` names the ceiling and narrower `dateRange` windows. (#34)
|
|
14
|
+
- **`hn_search_content` hits carry `type`**: `story`, `comment`, `poll`, `pollopt`, or `job`, when Algolia records one. A poll option renders as `Poll option by <author>` pointing to `hn_get_thread`. (#41)
|
|
15
|
+
- **Over-cap inputs are served at the cap instead of rejected**: `hn_get_stories` `count` up to 1,000 at 100, `hn_get_user` `submissionCount` up to 1,000 at 50, `hn_get_thread` `depth` up to 100 at 10 and `maxComments` up to 1,000 at 200, `hn_search_content` `count` up to 1,000 at 50. `cap` reports the value served and `notice` names the lever for the rest. Values above those ceilings are still rejected. (#45)
|
|
16
|
+
- **`hn_search_content` serves an over-cap `count` from the requested page's first hit**: the search runs as page `page × count / 50` at 50, and `page`, `totalPages`, and `criteria.count` describe that page of 50. (#45)
|
|
17
|
+
- **`hn_search_content` adds the error reason `count_page_unaligned`**: a `count` above 50 with a non-zero `page` whose first hit begins no page of 50 fails with it, naming a `count` and `page` that start at that hit. (#45)
|
|
18
|
+
- **`hn_get_thread` `nextCursor` is packed**: a base64url varint encoding that also carries the resolved story. Cursors issued by earlier releases still resume, and a cursor longer than 150,000 characters is rejected as `invalid_cursor`. (#43)
|
|
19
|
+
- **`hn_get_thread` rejects a cursor it did not issue** with the declared `invalid_cursor` reason, so the rejection logs at `notice` with the reason attached. (#36)
|
|
20
|
+
- **`hn_search_content` drops a leading `http://`, `https://`, or `www.` from a query that is a URL alone**, so submissions under either scheme, with or without `www.`, match. The output `query` and `notice` show what was searched. (#38)
|
|
21
|
+
- **`hn_search_content` job descriptions** (`job_text`) are returned as `text`; they are not keyword-searched or highlighted. (#41)
|
|
22
|
+
- **`hn_search_content` names the `author` casing rule** when an author-filtered first page is empty: `author` is an exact, case-sensitive match. (#39)
|
|
23
|
+
- **`hn_search_content` scopes `tags: "front_page"`** in the `notice` on an empty first page or whenever `dateRange` is set: it is the current front page only, with `tags: "story"` plus `dateRange` and `minPoints` as the alternative. (#40)
|
|
24
|
+
- **`hn_search_content` escapes the query** in the `content[]` heading and no-results line. (#35)
|
|
25
|
+
- **Framework sync**: `framework-skills/` synced to 0.13.15, `.env.example` lists `LOG_LLM_INTERACTIONS`, and the `check-framework-antipatterns.ts` patterns use POSIX space classes.
|
|
26
|
+
- **Tests**: worst-case timing checks measure the test thread's CPU time instead of wall clock. (#44)
|
|
27
|
+
|
|
28
|
+
## Fixed
|
|
29
|
+
|
|
30
|
+
- **`hn_get_thread` returns live replies below dead and deleted comments** at their true `depth`, with `parentId` naming the omitted comment. The comment stays out of `comments[]` and in the notice's counts; where the depth limit cuts its replies, `notice` names it by ID to pass as `itemId`. (#33)
|
|
31
|
+
- **`descendants` and `totalAvailable` are described as live-comment counts** in `hn_get_stories`, `hn_get_user`, and `hn_get_thread`. (#33)
|
|
32
|
+
- **`isOp` on a comment root marks replies by the story's author**, where it marked the root comment's author. The lookup follows at most 64 parent links and ends 20 seconds after the call starts. (#42)
|
|
33
|
+
- **A caller abort during a retry's backoff ends a `fetchItems` batch** instead of recording a failed slot. (#42)
|
|
34
|
+
|
|
35
|
+
## Dependencies
|
|
36
|
+
|
|
37
|
+
- `@cyanheads/mcp-ts-core` ^0.13.12 → ^0.13.15 (0.13.13: error envelopes drop `data.rootCause` and filesystem storage errors name the key, not the storage root; 0.13.14: tool-argument pre-validation repairs numeric and boolean strings, lone strings for arrays, and null optionals; 0.13.15: DuckDB canvases run with external access off and ZodError `data.issues` is bounded)
|
|
38
|
+
- `@modelcontextprotocol/server` 2.2.0 → 2.3.1 (transitive)
|
|
39
|
+
- `pino-pretty` ^13.1.3 → ^13.2.0
|
|
40
|
+
- `zod` ^4.6.5 → ^4.6.7
|
|
41
|
+
- Dev: `@types/node` ^26.6.4 → ^26.6.5
|
|
42
|
+
- Dev: `@vitest/coverage-istanbul` ^5.0.3 → ^5.0.5
|
|
43
|
+
- Dev: `ignore` ^7.0.11 → ^7.0.12
|
|
44
|
+
- Dev: `vitest` ^5.0.3 → ^5.0.5
|
|
45
|
+
- `packageManager` bun@1.4.2 → bun@1.4.3; Docker base images `oven/bun` 1.4.2 → 1.4.3
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-stories.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-stories.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"get-stories.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-stories.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAkBjE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA4QrB,CAAC"}
|
|
@@ -5,9 +5,12 @@
|
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
7
|
import { escapeInline, quoteBody } from '../markdown-escape.js';
|
|
8
|
+
import { servedAtCap } from '../served-at-cap.js';
|
|
8
9
|
import { decodeHtmlEntities, extractDomain, getHnService, normalizeUrl, settlePage, stripHtml, } from '../../../services/hn/hn-service.js';
|
|
9
|
-
/**
|
|
10
|
-
const
|
|
10
|
+
/** Most stories one call serves; a larger `count` is served at this cap. */
|
|
11
|
+
const COUNT_CAP = 100;
|
|
12
|
+
/** Largest `count` accepted; anything above it is rejected. */
|
|
13
|
+
const COUNT_CEILING = 1000;
|
|
11
14
|
export const getStories = tool('hn_get_stories', {
|
|
12
15
|
description: 'Fetch stories from an HN feed (top, new, best, ask, show, jobs), with title, URL, score, author, and comment count for each story.',
|
|
13
16
|
annotations: { readOnlyHint: true },
|
|
@@ -60,9 +63,9 @@ export const getStories = tool('hn_get_stories', {
|
|
|
60
63
|
.number()
|
|
61
64
|
.int()
|
|
62
65
|
.min(1)
|
|
63
|
-
.max(
|
|
66
|
+
.max(COUNT_CEILING)
|
|
64
67
|
.default(30)
|
|
65
|
-
.describe(
|
|
68
|
+
.describe(`Number of stories to return, at most ${COUNT_CAP} per call. A larger value is served at ${COUNT_CAP}, and the notice names the offset for the next page. Larger counts take longer.`),
|
|
66
69
|
offset: z
|
|
67
70
|
.number()
|
|
68
71
|
.int()
|
|
@@ -100,7 +103,10 @@ export const getStories = tool('hn_get_stories', {
|
|
|
100
103
|
.number()
|
|
101
104
|
.optional()
|
|
102
105
|
.describe('Unix timestamp when provided by HN. Omitted when unknown.'),
|
|
103
|
-
descendants: z
|
|
106
|
+
descendants: z
|
|
107
|
+
.number()
|
|
108
|
+
.optional()
|
|
109
|
+
.describe("HN's count of live comments in the thread (descendants); dead and deleted comments are not counted. Absent for jobs."),
|
|
104
110
|
text: z
|
|
105
111
|
.string()
|
|
106
112
|
.optional()
|
|
@@ -121,7 +127,10 @@ export const getStories = tool('hn_get_stories', {
|
|
|
121
127
|
.optional()
|
|
122
128
|
.describe('True when more stories remain beyond this page (hasMore). Absent on the last page of the feed.'),
|
|
123
129
|
shown: z.number().optional().describe('Number of stories returned on this page.'),
|
|
124
|
-
cap: z
|
|
130
|
+
cap: z
|
|
131
|
+
.number()
|
|
132
|
+
.optional()
|
|
133
|
+
.describe(`The count value served: as passed, or ${COUNT_CAP} when count was above that cap.`),
|
|
125
134
|
failedIds: z
|
|
126
135
|
.array(z.number())
|
|
127
136
|
.optional()
|
|
@@ -129,7 +138,7 @@ export const getStories = tool('hn_get_stories', {
|
|
|
129
138
|
notice: z
|
|
130
139
|
.string()
|
|
131
140
|
.optional()
|
|
132
|
-
.describe('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.'),
|
|
141
|
+
.describe('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 — noting when count was served at its per-call cap. Absent on the last page of a non-empty result with no failed IDs.'),
|
|
133
142
|
},
|
|
134
143
|
enrichmentTrailer: {
|
|
135
144
|
failedIds: { render: (ids) => `**Failed to load:** ${(ids ?? []).join(', ')}` },
|
|
@@ -137,7 +146,8 @@ export const getStories = tool('hn_get_stories', {
|
|
|
137
146
|
async handler(input, ctx) {
|
|
138
147
|
const hn = getHnService();
|
|
139
148
|
const feedIds = await hn.fetchFeed(input.feed, ctx);
|
|
140
|
-
const
|
|
149
|
+
const count = Math.min(input.count, COUNT_CAP);
|
|
150
|
+
const sliced = feedIds.slice(input.offset, input.offset + count);
|
|
141
151
|
const { items, failedIds } = settlePage(await hn.fetchItems(sliced, ctx));
|
|
142
152
|
const stories = items.map((item) => {
|
|
143
153
|
const url = normalizeUrl(item.url);
|
|
@@ -161,7 +171,7 @@ export const getStories = tool('hn_get_stories', {
|
|
|
161
171
|
failed: failedIds.length,
|
|
162
172
|
});
|
|
163
173
|
const total = feedIds.length;
|
|
164
|
-
const nextOffset = input.offset +
|
|
174
|
+
const nextOffset = input.offset + count;
|
|
165
175
|
const hasMore = nextOffset < total;
|
|
166
176
|
ctx.enrich({
|
|
167
177
|
total,
|
|
@@ -174,15 +184,16 @@ export const getStories = tool('hn_get_stories', {
|
|
|
174
184
|
? `Could not fetch ${failedIds.length} of ${sliced.length} items on this page (id${failedIds.length === 1 ? '' : 's'} ${failedIds.join(', ')}). Retry with offset: ${input.offset}, or pass an id as itemId to hn_get_thread to fetch that story alone.`
|
|
175
185
|
: undefined;
|
|
176
186
|
if (hasMore) {
|
|
177
|
-
const raiseCount = input.count <
|
|
187
|
+
const raiseCount = input.count < COUNT_CAP ? `, or raise count (max ${COUNT_CAP})` : '';
|
|
178
188
|
const nextPage = `Pass offset: ${nextOffset} for the next page${raiseCount}.`;
|
|
179
189
|
const pageStatus = stories.length === 0 && !failureMessage
|
|
180
190
|
? deadPageMessage
|
|
181
191
|
: `Showing items ${input.offset + 1}–${nextOffset} of ${total} in the ${input.feed} feed.`;
|
|
192
|
+
const overCap = input.count > COUNT_CAP ? servedAtCap('count', input.count, COUNT_CAP) : '';
|
|
182
193
|
ctx.enrich.truncated({
|
|
183
194
|
shown: stories.length,
|
|
184
|
-
cap:
|
|
185
|
-
guidance: [pageStatus, failureMessage, nextPage].filter(Boolean).join(' '),
|
|
195
|
+
cap: count,
|
|
196
|
+
guidance: [pageStatus, overCap, failureMessage, nextPage].filter(Boolean).join(' '),
|
|
186
197
|
});
|
|
187
198
|
}
|
|
188
199
|
else if (stories.length === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-stories.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-stories.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,SAAS,GACV,MAAM,6BAA6B,CAAC;AAErC,
|
|
1
|
+
{"version":3,"file":"get-stories.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-stories.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,6 +22,7 @@ export declare const getThread: import("@cyanheads/mcp-ts-core").ToolDefinition<
|
|
|
22
22
|
score: z.ZodOptional<z.ZodNumber>;
|
|
23
23
|
descendants: z.ZodOptional<z.ZodNumber>;
|
|
24
24
|
parent: z.ZodOptional<z.ZodNumber>;
|
|
25
|
+
storyId: z.ZodOptional<z.ZodNumber>;
|
|
25
26
|
poll: z.ZodOptional<z.ZodNumber>;
|
|
26
27
|
parts: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
|
|
27
28
|
deleted: z.ZodOptional<z.ZodLiteral<true>>;
|
|
@@ -53,8 +54,8 @@ export declare const getThread: import("@cyanheads/mcp-ts-core").ToolDefinition<
|
|
|
53
54
|
}, {
|
|
54
55
|
readonly reason: "invalid_cursor";
|
|
55
56
|
readonly code: JsonRpcErrorCode.InvalidParams;
|
|
56
|
-
readonly when: "The cursor was issued for a different itemId than the one passed with it.";
|
|
57
|
-
readonly recovery: "Pass
|
|
57
|
+
readonly when: "The cursor is not one this tool issued, was altered, or was issued for a different itemId than the one passed with it.";
|
|
58
|
+
readonly recovery: "Pass nextCursor unchanged, with the same itemId it was returned for, or omit cursor to start this item from the top.";
|
|
58
59
|
readonly severity: "notice";
|
|
59
60
|
}, {
|
|
60
61
|
readonly reason: "upstream_rejected";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-thread.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-thread.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAsB,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,
|
|
1
|
+
{"version":3,"file":"get-thread.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-thread.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAsB,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAiB,MAAM,+BAA+B,CAAC;AAmfhF,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAsZpB,CAAC"}
|