@cyanheads/hn-mcp-server 0.5.13 → 0.5.14
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/CLAUDE.md +17 -11
- package/Dockerfile +13 -7
- package/README.md +1 -1
- package/changelog/0.1.x/0.1.0.md +31 -0
- package/changelog/0.1.x/0.1.1.md +16 -0
- package/changelog/0.1.x/0.1.2.md +12 -0
- package/changelog/0.1.x/0.1.3.md +12 -0
- package/changelog/0.1.x/0.1.4.md +15 -0
- package/changelog/0.1.x/0.1.5.md +14 -0
- package/changelog/0.1.x/0.1.6.md +24 -0
- package/changelog/0.1.x/0.1.7.md +11 -0
- package/changelog/0.1.x/0.1.8.md +11 -0
- package/changelog/0.1.x/0.1.9.md +20 -0
- package/changelog/0.2.x/0.2.0.md +28 -0
- package/changelog/0.3.x/0.3.0.md +18 -0
- package/changelog/0.4.x/0.4.0.md +21 -0
- package/changelog/0.4.x/0.4.2.md +36 -0
- package/changelog/0.4.x/0.4.3.md +23 -0
- package/changelog/0.5.x/0.5.0.md +27 -0
- package/changelog/0.5.x/0.5.1.md +24 -0
- package/changelog/0.5.x/0.5.10.md +24 -0
- package/changelog/0.5.x/0.5.11.md +27 -0
- package/changelog/0.5.x/0.5.12.md +34 -0
- package/changelog/0.5.x/0.5.13.md +18 -0
- package/changelog/0.5.x/0.5.14.md +29 -0
- package/changelog/0.5.x/0.5.2.md +28 -0
- package/changelog/0.5.x/0.5.3.md +27 -0
- package/changelog/0.5.x/0.5.4.md +19 -0
- package/changelog/0.5.x/0.5.5.md +11 -0
- package/changelog/0.5.x/0.5.6.md +25 -0
- package/changelog/0.5.x/0.5.7.md +16 -0
- package/changelog/0.5.x/0.5.8.md +17 -0
- package/changelog/0.5.x/0.5.9.md +11 -0
- package/changelog/template.md +168 -0
- package/dist/services/hn/hn-service.d.ts.map +1 -1
- package/dist/services/hn/hn-service.js +28 -41
- package/dist/services/hn/hn-service.js.map +1 -1
- package/package.json +32 -22
- package/server.json +5 -5
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Reject fractional and blank/whitespace-only tool inputs; hn_search_content reports Algolia's own page count instead of a recomputation; hn_get_user's Firebase username segment is percent-encoded; hn_get_thread omits totalAvailable instead of rendering undefined. @cyanheads/mcp-ts-core ^0.10.9 → ^0.11.0."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.5.12 — 2026-07-28
|
|
8
|
+
|
|
9
|
+
## Changed
|
|
10
|
+
|
|
11
|
+
- **`bunfig.toml`** — adds `[install.security] scanner = "@socketsecurity/bun-security-scanner"` and a `minimumReleaseAge` of 3 days (`259200`s) on installed package versions, excluding `@cyanheads/mcp-ts-core` via `minimumReleaseAgeExcludes` so framework releases still adopt same-day.
|
|
12
|
+
- **`Dockerfile`** — the production stage's OTEL `bun add` gains `--omit=dev --ignore-scripts`, and both stages gain a BuildKit cache mount (`--mount=type=cache,target=/root/.bun/install/cache`) for Bun's install cache.
|
|
13
|
+
- **`.gitignore`** — `data/` anchored to `/data/`; the unanchored pattern also matched nested paths such as `src/data/`.
|
|
14
|
+
- **`devcheck.config.json`** — `@socketsecurity/bun-security-scanner` added to the depcheck ignore list (install-time-only, never imported); `typescript` dropped from the `outdated` allowlist now that TypeScript 7 is adopted below.
|
|
15
|
+
- **Skill sync** — vendored `skills/` (15 directories) and framework `scripts/*.ts` (7 files) resynced to `@cyanheads/mcp-ts-core` 0.11.0.
|
|
16
|
+
|
|
17
|
+
## Fixed
|
|
18
|
+
|
|
19
|
+
- **Fractional numeric inputs are rejected** — `count`/`offset` (`hn_get_stories`), `itemId`/`depth`/`maxComments` (`hn_get_thread`), `submissionCount` (`hn_get_user`), `count`/`page`/`minPoints` (`hn_search_content`), and `HN_CONCURRENCY_LIMIT` now require `.int()`. Fractional values previously passed validation and either silently truncated results or produced confusing upstream errors. [#10](https://github.com/cyanheads/hn-mcp-server/issues/10)
|
|
20
|
+
- **Blank and whitespace-only strings are rejected** — `hn_search_content`'s `query` and `author`, and `hn_get_user`'s `username`, are now `.trim()`-aware. A whitespace-only `query` no longer returns HN's global leaderboard, and a whitespace-only `author` no longer silently zeroes out results. [#9](https://github.com/cyanheads/hn-mcp-server/issues/9)
|
|
21
|
+
- **`hn_search_content` reports Algolia's own page count** — `totalPages` now mirrors the Algolia response's `nbPages` instead of recomputing `Math.ceil(nbHits / count)`, which overstated reachable pages by orders of magnitude on broad queries. [#11](https://github.com/cyanheads/hn-mcp-server/issues/11)
|
|
22
|
+
- **`hn_get_user` percent-encodes the username path segment** — `HnService.fetchUser` calls `encodeURIComponent` before building the Firebase URL, so a value like `../item/8863` stays one opaque `/user/` segment instead of escaping to `/item/`. [#13](https://github.com/cyanheads/hn-mcp-server/issues/13)
|
|
23
|
+
- **`hn_get_thread` omits `totalAvailable` instead of rendering it as `undefined`** — comment and job roots don't report `descendants`; the enrichment call now only keys `totalAvailable` when HN provides a value. [#14](https://github.com/cyanheads/hn-mcp-server/issues/14)
|
|
24
|
+
|
|
25
|
+
## Dependencies
|
|
26
|
+
|
|
27
|
+
- `@cyanheads/mcp-ts-core` ^0.10.9 → ^0.11.0
|
|
28
|
+
- `typescript` ^6.0.3 → ^7.0.2
|
|
29
|
+
- `@biomejs/biome` ^2.5.0 → ^2.5.5
|
|
30
|
+
- `@types/node` ^26.0.0 → ^26.1.1
|
|
31
|
+
- `ignore` ^7.0.5 → ^7.0.6
|
|
32
|
+
- `tsc-alias` ^1.8.17 → ^1.9.1
|
|
33
|
+
- `vitest` ^4.1.9 → ^4.1.10
|
|
34
|
+
- new devDependency `@socketsecurity/bun-security-scanner` ^1.1.2 — the `bunfig.toml` install-time scanner
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "hn_get_user gains submissionOffset to page through a user's full submission history; hn_search_content gains a compact view that drops duplicated body text; upstream HTTP failures now classify onto a typed reason and recovery hint instead of a raw fetch error."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.5.13 — 2026-07-28
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`hn_get_user`** — `submissionOffset` (integer, min 0, default 0) pages through `user.submitted` in windows of `submissionCount`, so histories beyond the first page are reachable. Enrichment echoes the applied `submissionOffset` and either the next offset to request or the valid range when the offset is past the end. [#12](https://github.com/cyanheads/hn-mcp-server/issues/12)
|
|
12
|
+
- **`hn_search_content`** — `view: "full" | "compact"` (default `"full"`) controls per-hit body projection. `"compact"` omits `text` and `highlights.text` — the pair that can repeat a long comment body twice per hit — while keeping id, title, url, domain, author, points, comment count, timestamp, parent story, title highlight, and `matchedWords`. The projection is applied before either output surface is built, so `structuredContent` and `content[]` stay equivalent. [#15](https://github.com/cyanheads/hn-mcp-server/issues/15)
|
|
13
|
+
|
|
14
|
+
## Changed
|
|
15
|
+
|
|
16
|
+
- **`HnService`** — every fetch site now routes through a shared `getJson` helper wrapped in `withUpstreamHttpErrors`, which rewrites a non-2xx `FetchHttpError` into a classified `McpError` carrying `data.reason` and `data.recovery.hint`. Reasons: `upstream_rejected` (4xx other than 429, `InvalidParams`), `upstream_rate_limited` (429, `RateLimited`), `upstream_unavailable` (5xx, `ServiceUnavailable`). The wrapper sits outside `withRetry`, so retry eligibility, `Retry-After` handling, timeouts, and caller aborts still classify against the framework's original error. The upstream URL and verbatim response body are dropped from the client-facing message and `data`, staying only on the `cause` chain. [#16](https://github.com/cyanheads/hn-mcp-server/issues/16)
|
|
17
|
+
- **`parseJsonBody`** — a 200 response whose body is neither an HTML error page nor valid JSON now classifies as `upstream_malformed` (`ServiceUnavailable`) instead of letting a raw `SyntaxError` — which quotes the offending body back at the client — escape uncaught. [#16](https://github.com/cyanheads/hn-mcp-server/issues/16)
|
|
18
|
+
- **`hn_get_stories`**, **`hn_get_thread`**, **`hn_get_user`**, **`hn_search_content`** — each tool's `errors[]` contract now declares `upstream_rejected`, `upstream_rate_limited`, `upstream_unavailable`, `upstream_html`, and `upstream_malformed`, matching the reasons `HnService` can now throw.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "MCP SDK v2 compatibility, explicit stateless HTTP serving, and current framework-managed tooling"
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.5.14 — 2026-08-24
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **Community health files** — adds contribution and conduct guidance alongside the existing security policy.
|
|
12
|
+
|
|
13
|
+
## Changed
|
|
14
|
+
|
|
15
|
+
- **MCP SDK v2 compatibility** — HTTP serves both protocol revision 2026-07-28 and the 2025 era; undeclared top-level tool inputs are rejected by name, and tool failures advertise a structured error envelope.
|
|
16
|
+
- **HTTP session mode** — self-hosted configuration and the container explicitly use stateless serving; the schema's `auto` default remains documented as resolving to stateful.
|
|
17
|
+
- **Container build** — Bun `1.3.14` → `1.4.0`, native build stages use `BUILDPLATFORM`, and production installs omit the framework's optional peer tiers.
|
|
18
|
+
- **TypeScript and tests** — the typecheck covers `tests/`, build emission uses a dedicated config, and the Vitest suite uses typed error-contract contexts across all 274 tests.
|
|
19
|
+
- **Project tooling** — framework-managed scripts, skills, package metadata, plugin metadata, and bundle exclusions are synchronized with the current scaffold.
|
|
20
|
+
- **Security contact** — vulnerability reports use `security@caseyjhand.com`.
|
|
21
|
+
|
|
22
|
+
## Dependencies
|
|
23
|
+
|
|
24
|
+
- `@cyanheads/mcp-ts-core` `^0.11.0` → `^0.12.3`
|
|
25
|
+
- `@biomejs/biome` `^2.5.5` → `^2.5.10`
|
|
26
|
+
- `@types/node` `^26.1.1` → `^26.2.0`
|
|
27
|
+
- `tsc-alias` `^1.9.1` → `^1.9.2`
|
|
28
|
+
- `vitest` `^4.1.10` → `^4.1.11`
|
|
29
|
+
- `@vitest/coverage-istanbul` `^4.1.11` added; `pino-pretty` `^13.1.3` moved to runtime dependencies; direct `@hono/otel` `^1.1.2` removed in favor of the container's opt-in telemetry install.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Maintenance + capability release. Adopts the MCP spec server-level `instructions` field on `createApp()` so clients forward orientation text (item types, ID reuse, case-sensitive usernames, sparsity) to the model. Framework `^0.8.20 → ^0.9.1` brings Workers `nodejs_compat` fix, SSRF hardening, gated `tasks` capability, build-time-only lint."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.5.2 — 2026-05-16
|
|
8
|
+
|
|
9
|
+
Maintenance + capability release. Adopts the MCP spec's server-level `instructions` field on `createApp()` so spec-compliant clients forward orientation text (HN item types, ID reuse across tools, case-sensitive usernames, field sparsity) to the model as session context — previously this text had to live in every tool description. Pulls in the framework's 0.9.x line, which fixes Cloudflare Workers boot under `nodejs_compat`, hardens SSRF DNS validation in Workers, broadens IPv6 SSRF coverage, gates the experimental `tasks` capability on actual task-tool registration (unblocks MCP spec `2025-06-18` strict-parse clients), and moves definition linting to build-time only (faster cold starts). No application code changes beyond the `instructions` adoption; no breaking changes for this server's tool surface.
|
|
10
|
+
|
|
11
|
+
## Added
|
|
12
|
+
|
|
13
|
+
- `src/index.ts`: server-level `instructions` string on `createApp()` ([cyanheads/mcp-ts-core#91](https://github.com/cyanheads/mcp-ts-core/issues/91)). Sent on every `initialize` response and forwarded by spec-compliant clients to the model. Names the four tools, item type union (`story`, `comment`, `job`, `poll`, `pollopt`), ID reuse across tools, case-sensitive usernames, and the "treat absent fields as unknown" sparsity contract — moves session-level orientation out of per-tool description repetition.
|
|
14
|
+
|
|
15
|
+
## Changed
|
|
16
|
+
|
|
17
|
+
- Bumped `@cyanheads/mcp-ts-core` from `^0.8.20` to `^0.9.1`. Spans two framework releases:
|
|
18
|
+
- **0.9.0**: `instructions` field on entry points; Workers now boot and serve MCP JSON-RPC under `nodejs_compat` (previous detection used `!process.versions.node`, which is truthy under compat); five-rule cross-vendor portability lint family (`schema-format-portability` error-level default-on; warning-level `schema-anyof-needs-type`, `schema-no-discriminator-keyword`; opt-in `schema-no-defs`, `schema-dialect-tag`); definition linting moved to build-time only (no longer gates `createApp()` startup); RFC 8414 §3 path-suffixed `/.well-known/oauth-protected-resource/{path}` mount; SSRF DNS validation now enforced in Workers and IPv6 blocklist broadened (IPv4-mapped, ULA, link-local, multicast); `FileSystemProvider` re-validates `tenantId` at the storage boundary; rate-limit metric cardinality bounded ([cyanheads/mcp-ts-core#124](https://github.com/cyanheads/mcp-ts-core/issues/124), [#91](https://github.com/cyanheads/mcp-ts-core/issues/91), [#132](https://github.com/cyanheads/mcp-ts-core/issues/132), [#70](https://github.com/cyanheads/mcp-ts-core/issues/70), [#72](https://github.com/cyanheads/mcp-ts-core/issues/72), [#114](https://github.com/cyanheads/mcp-ts-core/issues/114)).
|
|
19
|
+
- **0.9.1**: `tasks` capability advertisement gated on actual task-tool registration (fixes strict-parse MCP `2025-06-18` clients); new `Context.notifyToolListChanged` / `notifyPromptListChanged` notifiers; OTel `deployment.environment.name` migrated to typed `ATTR_DEPLOYMENT_ENVIRONMENT_NAME`; `fast-xml-parser` pinned to exact `5.7.3`; OTel exporter/instrumentation refresh `^0.217 → ^0.218`.
|
|
20
|
+
- Portability lint impact: this server's four tools were already free of `z.url()`/`z.cuid()`/etc. constructs that would trip `schema-format-portability` (default-on, error). `bun run lint:mcp` and `bun run devcheck` pass clean.
|
|
21
|
+
- `scripts/build-changelog.ts` summary cap raised `250 → 350` chars ([cyanheads/mcp-ts-core#129](https://github.com/cyanheads/mcp-ts-core/issues/129)) — synced from upstream; 250 was forcing operator-relevant context out of rollup summaries.
|
|
22
|
+
- `scripts/devcheck.ts` `bun outdated` parser fix — `bun outdated` emits markdown-style rows (`| pkg | … |`) with an empty leading cell, so `split('|')[0]` was always empty and the allowlist never matched. Now reads index `[1]` and strips the `(dev|peer|prod|optional)` workspace marker so bare package names match. Synced from upstream framework devcheck.
|
|
23
|
+
- Refreshed project skills synced from `mcp-ts-core@0.9.0`/`0.9.1` (no version regressions): `add-tool` 2.8 → 2.9 (mutator response design subsection + unit-bearing numeric-name checklist item), `api-errors` 1.5 → 1.6 (`When not to throw` section), `api-linter` 1.2 → 1.3 (full portability rule family documented), `api-workers` 1.3 → 1.4 (`instructions` resolver form on `WorkerHandlerOptions`), `design-mcp-server` 2.10 → 2.11, `field-test` 2.3 → 2.4 (mutator-trigger situational row), `polish-docs-meta` 1.7 → 1.8 (`OTEL_ENABLED` README template now links to framework telemetry docs), `tool-defs-analysis` 1.1 → 1.2 (audit now walks 12 categories — added mutator observability and unit-bearing numeric names). All propagated to `.claude/skills/`.
|
|
24
|
+
- Dependency refresh: `@cyanheads/mcp-ts-core ^0.8.20 → ^0.9.1`, `@types/node ^25.6.2 → ^25.8.0`, `vitest ^4.1.5 → ^4.1.6`.
|
|
25
|
+
|
|
26
|
+
## Tests
|
|
27
|
+
|
|
28
|
+
- 147 passing. No test changes — `instructions` is verified by the framework's own suite.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Field-test refinements to two `format()` output paths. `hn_get_stories` now distinguishes offset-past-end from genuinely-empty feeds. `hn_get_user` no longer duplicates the item type when rendering a typeless submission. Also migrates the project to the framework's directory-based changelog convention."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.5.3 — 2026-05-21
|
|
8
|
+
|
|
9
|
+
## Changed
|
|
10
|
+
|
|
11
|
+
- `hn_get_stories` `format()`: three-branch empty-result handling. When `stories=[] && total>0 && offset>=total`, render `"<feed> feed — offset N is past the end (feed has M items)"` instead of bare `"<feed> feed — no stories"`. When `offset<total` but the page still came back empty (all items filtered out as dead/deleted), render `"<feed> feed — no live stories on this page (offset:N, feed total:M)"`. The original `"<feed> feed — no stories"` text is now reserved for `total===0`. Closes a parity gap between `structuredContent.total` and the `content[]` text — format-only clients (Claude Desktop) previously had no way to tell an over-paginated query apart from an empty feed.
|
|
12
|
+
- `hn_get_user` `format()`: submission rendering no longer duplicates the item type. The meta line skips the type token when the title fell back to `[${s.type}]`, so a typeless comment now renders as `**[comment]** — id:N | ...` instead of `**[comment]** — id:N | comment | ...`. Titled stories continue to carry the type token in meta (still shown exactly once). Title fallback also switched from `??` to `||` so an empty-string title (theoretical: HN-supplied title that strips to nothing) falls through to `[${s.type}]` instead of producing `**** — id:N | ...` with no type at all. Test invariant: type appears exactly once on every submission line.
|
|
13
|
+
|
|
14
|
+
## Added
|
|
15
|
+
|
|
16
|
+
- `changelog/<major.minor>.x/<version>.md` directory-based per-version changelog convention (framework standard). All 18 historical entries migrated from the monolithic `CHANGELOG.md` via `scripts/split-changelog.ts` and backfilled with `summary`/`breaking`/`security` frontmatter. `CHANGELOG.md` is now a 75-line navigation index regenerated by `bun run changelog:build`. `bun run changelog:check` gates devcheck against drift.
|
|
17
|
+
- `package.json` scripts: `changelog:build` and `changelog:check`.
|
|
18
|
+
- `changelog/template.md` pristine reference synced from `@cyanheads/mcp-ts-core/templates/changelog/template.md`.
|
|
19
|
+
|
|
20
|
+
## Tests
|
|
21
|
+
|
|
22
|
+
- 153 passing (up from 150). Added three branches to `get-stories.tool.test.ts` covering offset-past-end (with singular/plural item count), and the all-filtered-on-page case. Added an `it.each` parametric test to `get-user.tool.test.ts` that asserts the item type is rendered exactly once across undefined, empty, and real title shapes.
|
|
23
|
+
|
|
24
|
+
## Maintenance
|
|
25
|
+
|
|
26
|
+
- `@types/node ^25.8.0 → ^25.9.1`, `vitest ^4.1.6 → ^4.1.7` (both patch). No application impact.
|
|
27
|
+
- `scripts/devcheck.ts` resynced from `@cyanheads/mcp-ts-core` — `bun outdated` parser refactored into two filter passes with an extracted `stripWorkspaceMarker` helper. Functionally equivalent.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Maintenance. `@cyanheads/mcp-ts-core ^0.9.1 → ^0.9.6`, `zod` added as explicit dependency. `manifest.json` + `.mcpbignore` scaffolded for MCPB bundle support. Install badges added to README. New scripts: `list-skills`, `lint:packaging`, `bundle`, `audit:refresh`."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.5.4 — 2026-05-23
|
|
8
|
+
|
|
9
|
+
## Maintenance
|
|
10
|
+
|
|
11
|
+
- `@cyanheads/mcp-ts-core ^0.9.1 → ^0.9.6`. Span across five patch releases; no breaking changes for this server.
|
|
12
|
+
- `zod ^4.4.3` added as an explicit dependency (previously transitive via mcp-ts-core).
|
|
13
|
+
- `manifest.json` scaffolded — MCPB bundle descriptor for Claude Desktop one-click install.
|
|
14
|
+
- `.mcpbignore` scaffolded — excludes source, devDeps, and scripts from the bundle.
|
|
15
|
+
- `package.json` scripts: `list-skills`, `lint:packaging`, `bundle` (`@anthropic-ai/mcpb pack`), `audit:refresh`.
|
|
16
|
+
- `scripts/lint-packaging.ts` + `scripts/list-skills.ts` added (synced from mcp-ts-core).
|
|
17
|
+
- `scripts/devcheck.ts` resynced from mcp-ts-core.
|
|
18
|
+
- README: install badges row (Claude Desktop MCPB, Cursor deeplink, VS Code deeplink). Docker config snippet added to self-hosted section. Badge row reordered; description line tightened.
|
|
19
|
+
- CLAUDE.md: `ctx.tenantId` row added to Context table; `list-skills`, `lint:packaging`, `bundle`, `audit:refresh` added to Commands table.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "Fix duplicate `hono` installs causing `@hono/otel` crash on every HTTP request. `hono ^4.12.22` added as direct dependency to force deduplication."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.5.5 — 2026-05-23
|
|
8
|
+
|
|
9
|
+
## Bug Fix
|
|
10
|
+
|
|
11
|
+
- **`hono` added as direct dependency (`^4.12.22`)** — the lockfile resolved `hono` to 4.12.19 at the top level while `mcp-ts-core` needed `^4.12.22`, causing bun to install a second copy nested inside `mcp-ts-core/node_modules/`. Two Hono instances mean two distinct `GET_MATCH_RESULT` symbols; `@hono/otel` imported `matchedRoutes` from the top-level copy but routing ran through the nested copy, so every HTTP request threw `TypeError: undefined is not an object (evaluating 'c.req[GET_MATCH_RESULT][0]')` and returned 500. Adding `hono` as a direct dependency forces a single hoisted copy, eliminating the symbol mismatch.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "@cyanheads/mcp-ts-core ^0.9.6 → ^0.9.13: 413 body cap, HTTP session-init gate, quieter client-error logging, GET /mcp surfaces keywords; dep refresh; package.json keyword additions"
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.5.6 — 2026-05-28
|
|
8
|
+
|
|
9
|
+
## Changed
|
|
10
|
+
|
|
11
|
+
- **`@cyanheads/mcp-ts-core` ^0.9.6 → ^0.9.13** — framework adoption covering:
|
|
12
|
+
- **`MCP_HTTP_MAX_BODY_BYTES`** — configurable inbound body cap (default 1 MiB); oversized requests rejected with HTTP 413 before session allocation or body parsing.
|
|
13
|
+
- **HTTP session-init gate** — stateful HTTP mode rejects non-`initialize` requests that arrive without an `Mcp-Session-Id` header with HTTP 400, preventing uninitialized sessions from being minted on first contact.
|
|
14
|
+
- **Quieter client-error logging** — expected 401, 403, 400, and 404 responses now logged at `warning` instead of full error-pipeline with stack traces.
|
|
15
|
+
- **`GET /mcp` keywords** — `package.json` `keywords` now included in the status JSON alongside `name`, `version`, and `description`.
|
|
16
|
+
- **`src/index.ts`** — `landing: { requireAuth: false }` added; restores full tool-inventory visibility on the landing page for this public-catalog deployment (framework 0.9.13 default gates inventory behind auth when `MCP_AUTH_MODE` is `jwt` or `oauth`).
|
|
17
|
+
- **`manifest.json`** — `repository`, `homepage`, and `license` fields added.
|
|
18
|
+
- **`package.json` keywords** — `typescript`, `bun`, `stdio`, `streamable-http` added.
|
|
19
|
+
- **Skill sync** — `git-wrapup`, `code-simplifier` skills added; `migrate-mcp-ts-template` removed; bulk refresh across field-test, maintenance, polish-docs-meta, design-mcp-server, api-canvas, api-config, release-and-publish, report-issue-framework.
|
|
20
|
+
|
|
21
|
+
## Dependencies
|
|
22
|
+
|
|
23
|
+
- `@cyanheads/mcp-ts-core` ^0.9.6 → ^0.9.13
|
|
24
|
+
- `hono` ^4.12.22 → ^4.12.23
|
|
25
|
+
- `@biomejs/biome` ^2.4.15 → ^2.4.16
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "enrichment adoption — ranked-feed and search tools surface result context (counts, query echo, empty-result guidance) in a typed enrichment block reaching both structuredContent JSON and content[] markdown trailer"
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.5.7 — 2026-05-30
|
|
8
|
+
|
|
9
|
+
## Changed
|
|
10
|
+
|
|
11
|
+
- **`hn_get_stories`** — `total`, `offset`, `hasMore` moved from `output` to `enrichment`; `notice` (empty-result guidance) added to `enrichment`. `structuredContent` field `offset` renamed to match its new location; value preserved.
|
|
12
|
+
- **`hn_get_thread`** — `totalLoaded`, `totalAvailable` moved from `output` to `enrichment`; `omitted` object replaced by `notice` string in `enrichment` (consolidates deleted/dead counts and pagination hint into one field).
|
|
13
|
+
- **`hn_search_content`** — `totalHits`, `page`, `totalPages` moved from `output` to `enrichment`; `message` renamed to `notice` in `enrichment`. `query` stays in `output`.
|
|
14
|
+
- **Tests** — updated across all three tool test files to match the revised `output` + `enrichment` shapes.
|
|
15
|
+
- **`@cyanheads/mcp-ts-core` ^0.9.13 → ^0.9.16** — enrichment API adoption.
|
|
16
|
+
- **Skill sync** — bulk refresh across `add-tool`, `add-app-tool`, `add-service`, `api-context`, `api-linter`, `design-mcp-server`, `git-wrapup`, `maintenance`, `polish-docs-meta`, `setup`; `devcheck` skill removed (superseded by the `devcheck.config.json`-driven script).
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "@cyanheads/mcp-ts-core ^0.9.16 → ^0.9.21 — per-request log context fix, secret-stripped error messages, withRetry fail-fast on non-retryable errors"
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.5.8 — 2026-06-02
|
|
8
|
+
|
|
9
|
+
## Changed
|
|
10
|
+
|
|
11
|
+
- **`@cyanheads/mcp-ts-core` ^0.9.16 → ^0.9.21** — framework adoption; see below for notable changes.
|
|
12
|
+
- **HTTP transport per-request log context** — per-request logs and traces now carry fresh request + trace/span IDs instead of the frozen boot context.
|
|
13
|
+
- **`fetchWithTimeout`** — strips query-string secrets (e.g. `?api_key=`) from error messages and logs.
|
|
14
|
+
- **`withRetry`** — fails fast on non-retryable errors; `ctx.fail` auto-populates the `retryable` flag.
|
|
15
|
+
- **Skill sync** — `add-tool`, `add-service`, `api-canvas`, `api-context`, `api-linter`, `api-utils`, `design-mcp-server`, `release-and-publish` updated; `api-mirror` and `orchestrations` added.
|
|
16
|
+
- **Scripts** — `devcheck.ts`, `check-skill-versions.ts`, `release-github.ts` added; `release:github` npm script added.
|
|
17
|
+
- **`vitest` ^4.1.7 → ^4.1.8**
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "hn_get_user: surface submission pagination notice via enrichment block"
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.5.9 — 2026-06-04
|
|
8
|
+
|
|
9
|
+
## Fixed
|
|
10
|
+
|
|
11
|
+
- **`hn_get_user` pagination notice** — adds `enrichment.notice` and calls `ctx.enrich.notice()` when `includeSubmissions` is true and the resolved (live) submission count is less than `totalSubmissions`. The notice reads: `Showing N of M submissions. Raise submissionCount (max 50) for more.` Resolves [#8](https://github.com/cyanheads/hn-mcp-server/issues/8).
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
---
|
|
2
|
+
# FORMAT REFERENCE — do not edit. Copy this file to
|
|
3
|
+
# `changelog/<major.minor>.x/<version>.md` (e.g. `changelog/0.8.x/0.8.6.md`)
|
|
4
|
+
# to author a new release. Set that file's H1 to `# <version> — YYYY-MM-DD`
|
|
5
|
+
# with a concrete date.
|
|
6
|
+
|
|
7
|
+
# Required. One-line GitHub Release-style headline. 350 character cap — a
|
|
8
|
+
# ceiling, not a target. Default short and scannable. Don't pad, don't stitch
|
|
9
|
+
# unrelated changes with commas/semicolons into an inventory — pick the
|
|
10
|
+
# headline, like a tag's theme line. Quotes required: unquoted YAML treats
|
|
11
|
+
# `: ` inside the value as a key separator and fails GitHub's strict parser.
|
|
12
|
+
summary: ""
|
|
13
|
+
|
|
14
|
+
# Set `true` when consumers must change code to upgrade: API removals,
|
|
15
|
+
# signature changes, config renames, behavior changes that break existing
|
|
16
|
+
# usage. Flagged as `Breaking` in the rollup.
|
|
17
|
+
breaking: false
|
|
18
|
+
|
|
19
|
+
# Set `true` ONLY for a security fix in THIS project's own source code — a
|
|
20
|
+
# vulnerability or hardening in code you ship. A dependency or transitive CVE
|
|
21
|
+
# bump is routine maintenance, NOT a security release: record it under
|
|
22
|
+
# `## Dependencies` (with the advisory ID) and leave this `false`. When true,
|
|
23
|
+
# pairs with the `## Security` section below and flags `Security` in the rollup.
|
|
24
|
+
security: false
|
|
25
|
+
|
|
26
|
+
# Optional free-form notes for maintenance agents processing this release.
|
|
27
|
+
# Not rendered in CHANGELOG — consumed by agents running `maintenance` on
|
|
28
|
+
# downstream servers. ADOPTION STEPS ONLY — new files to create, fields to
|
|
29
|
+
# populate, one-time migration steps. Never a second rendering of the body:
|
|
30
|
+
# if a body bullet already says it, name the bullet's symbol instead of
|
|
31
|
+
# re-explaining. Omit the field entirely when there's nothing to say.
|
|
32
|
+
# agent-notes: |
|
|
33
|
+
# <instructions for downstream maintenance agents>
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
# <version> — YYYY-MM-DD
|
|
37
|
+
|
|
38
|
+
<!--
|
|
39
|
+
AUTHORING GUIDE — applies to the new per-version file you create from this
|
|
40
|
+
template.
|
|
41
|
+
|
|
42
|
+
Audience: someone scanning release notes to decide what affects them. Lead
|
|
43
|
+
each bullet with the symbol or concept name in **bold** so they can skip
|
|
44
|
+
what's irrelevant and zoom in on what's not.
|
|
45
|
+
|
|
46
|
+
Tone: terse, fact-dense, not verbose. Bullet shape: **symbol** + what
|
|
47
|
+
changed + at most one consumer-facing caveat. One sentence by default, two
|
|
48
|
+
when the second carries weight — a bullet past ~40 words or three sentences
|
|
49
|
+
is wrong. The depth lives one hop away: the linked issue carries the why,
|
|
50
|
+
the commit diff carries the how. The changelog names what changed and what
|
|
51
|
+
a consumer does about it; a reader who wants mechanism opens the link.
|
|
52
|
+
|
|
53
|
+
Model length on THIS guide, never on the previous entry — entries modeled
|
|
54
|
+
on entries compound.
|
|
55
|
+
|
|
56
|
+
Cut (each has shipped as a wall of text; these are the cruft):
|
|
57
|
+
- History/justification narration — how the bug worked, why the old
|
|
58
|
+
behavior was wrong. One short clause at most; the issue carries the story.
|
|
59
|
+
- Design-rationale defense — "chosen over Y because…", "guarding the
|
|
60
|
+
getter is not enough…". That is the author arguing with a reviewer;
|
|
61
|
+
reviewers read the PR, not the changelog.
|
|
62
|
+
- Defensive unchanged-clauses — "X is unchanged", "byte-identical to
|
|
63
|
+
<prev>". Keep one only where its absence would cause a real misread,
|
|
64
|
+
as a short parenthetical.
|
|
65
|
+
- Edge-case inventories — marker lists, not-flagged lists, escape tables.
|
|
66
|
+
Tests and the issue carry those.
|
|
67
|
+
- Mechanism walkthroughs (JSDoc, CLAUDE.md/AGENTS.md, or the relevant
|
|
68
|
+
skill own those), ceremonial framings ("This release introduces…"),
|
|
69
|
+
backwards-compat paragraphs, file-by-file test enumerations. Prefer
|
|
70
|
+
code/symbol names over English re-explanations.
|
|
71
|
+
|
|
72
|
+
Verified ≠ included: the every-claim-verified-from-the-diff rule bounds
|
|
73
|
+
the TRUTH of what you write, never the AMOUNT.
|
|
74
|
+
|
|
75
|
+
Example — same fact, right size:
|
|
76
|
+
|
|
77
|
+
TOO LONG: **`fetchWithTimeout`'s `timeoutMs` bounds the whole exchange**
|
|
78
|
+
(#341). `fetch` resolves once headers arrive and the deadline was
|
|
79
|
+
cleared as the helper returned, so a peer that answered promptly and
|
|
80
|
+
then stalled the stream held the request open indefinitely. A 2xx
|
|
81
|
+
carrying a body now comes back as a passthrough wrapper that disarms
|
|
82
|
+
the deadline when the body closes, errors, or is cancelled; …
|
|
83
|
+
[+90 more words of mechanism and edge cases]
|
|
84
|
+
|
|
85
|
+
RIGHT: **`fetchWithTimeout`'s `timeoutMs` now bounds the whole
|
|
86
|
+
exchange, not just the headers** (#341). A stalled body aborts with
|
|
87
|
+
the same `Timeout` error; the returned `Response` is a wrapper, so
|
|
88
|
+
identity assertions (`toBe(response)`) no longer hold.
|
|
89
|
+
|
|
90
|
+
Narrative intro: skip by default. Add one short sentence only when the
|
|
91
|
+
release theme genuinely needs framing the bullets can't carry. When many
|
|
92
|
+
bullets share one upgrade consequence, state it ONCE — intro line or
|
|
93
|
+
agent-notes — never per bullet.
|
|
94
|
+
|
|
95
|
+
Sections: Keep a Changelog order — Added, Changed, Deprecated, Removed,
|
|
96
|
+
Fixed, Security. Include only sections with entries; delete the rest
|
|
97
|
+
(including the commented-out scaffolding below). Don't ship empty headers.
|
|
98
|
+
|
|
99
|
+
Include: every distinct fact a reader needs to adopt or audit the release —
|
|
100
|
+
new exports, signatures, lint rule IDs, env vars, breaking changes, version
|
|
101
|
+
bumps on shipped skills. Nothing more.
|
|
102
|
+
|
|
103
|
+
Links: link issues, PRs, docs, or skills where they help a reader jump to
|
|
104
|
+
context. Once per item per entry — don't re-link the same issue in summary,
|
|
105
|
+
narrative, and bullet. Skip links for inline symbol names; code spans speak
|
|
106
|
+
for themselves.
|
|
107
|
+
|
|
108
|
+
Issue/PR URLs: use full URLs. GitHub's bare `#NN` auto-link only resolves
|
|
109
|
+
inside its own UI, not in npm reads or local editors.
|
|
110
|
+
|
|
111
|
+
[#38](https://github.com/cyanheads/mcp-ts-core/issues/38) ← issue
|
|
112
|
+
[#42](https://github.com/cyanheads/mcp-ts-core/pull/42) ← PR
|
|
113
|
+
|
|
114
|
+
Verify numbers exist before linking (`gh issue view NN`, `gh pr view NN`).
|
|
115
|
+
Never speculate on a future number — `#42` for an upcoming PR silently
|
|
116
|
+
resolves to whatever real item already owns 42, and timeline previews pull
|
|
117
|
+
in that unrelated item's metadata.
|
|
118
|
+
|
|
119
|
+
TAG ANNOTATIONS — the annotated tag body renders as the GitHub Release body
|
|
120
|
+
via `gh release create --notes-from-tag`. The tag is a derivative of this
|
|
121
|
+
changelog entry — a condensed, scannable version, not a copy. Format:
|
|
122
|
+
|
|
123
|
+
<theme — omit version number, GitHub prepends it>
|
|
124
|
+
← blank line
|
|
125
|
+
<1-2 sentence context: what this release does>
|
|
126
|
+
← blank line
|
|
127
|
+
Dependency bumps: ← section header
|
|
128
|
+
← blank line
|
|
129
|
+
- `@cyanheads/mcp-ts-core` ^0.9.1 → ^0.9.6 ← bullet
|
|
130
|
+
← blank line
|
|
131
|
+
Changed: ← only sections with entries
|
|
132
|
+
← blank line
|
|
133
|
+
- `format()` output includes `query` in text mode
|
|
134
|
+
← blank line
|
|
135
|
+
Added:
|
|
136
|
+
← blank line
|
|
137
|
+
- `manifest.json` scaffolded for MCPB bundle support
|
|
138
|
+
- Install badges (Claude Desktop, Cursor, VS Code)
|
|
139
|
+
← blank line
|
|
140
|
+
<N> tests pass; `bun run devcheck` clean. ← footer
|
|
141
|
+
|
|
142
|
+
Never a flat comma-separated string. Always structured markdown with
|
|
143
|
+
sections. The tag must scan well as a rendered GitHub Release page.
|
|
144
|
+
-->
|
|
145
|
+
|
|
146
|
+
## Added
|
|
147
|
+
|
|
148
|
+
-
|
|
149
|
+
|
|
150
|
+
## Changed
|
|
151
|
+
|
|
152
|
+
-
|
|
153
|
+
|
|
154
|
+
<!-- ## Deprecated
|
|
155
|
+
|
|
156
|
+
- -->
|
|
157
|
+
|
|
158
|
+
<!-- ## Removed
|
|
159
|
+
|
|
160
|
+
- -->
|
|
161
|
+
|
|
162
|
+
## Fixed
|
|
163
|
+
|
|
164
|
+
-
|
|
165
|
+
|
|
166
|
+
<!-- ## Security
|
|
167
|
+
|
|
168
|
+
- -->
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hn-service.d.ts","sourceRoot":"","sources":["../../../src/services/hn/hn-service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"hn-service.d.ts","sourceRoot":"","sources":["../../../src/services/hn/hn-service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAUtD,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAmB9E,8CAA8C;AAC9C,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMvD;AAED,wEAAwE;AACxE,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyB9C;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM1D;AAED,gDAAgD;AAChD,wBAAgB,YAAY,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAEpE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAOzE;AAED,gDAAgD;AAChD,wBAAgB,eAAe,CAAC,KAAK,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,CAElE;AA6HD,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAE1C,YAAY,gBAAgB,EAAE,MAAM,EAEnC;IAED;;;;OAIG;IACH,OAAO,CAAC,OAAO;IAmBf,mFAAmF;IACnF,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAE1D;IAED;;;;;OAKG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOhE;IAED,yEAAyE;IACzE,SAAS,CAAC,IAAI,EAAE,UAAU,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAG3D;IAED;;;;OAIG;IACG,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAyBxE;IAED,uEAAuE;IACvE,MAAM,CACJ,MAAM,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC5B,IAAI,EAAE,WAAW,GAAG,MAAM,CAAC;QAC3B,SAAS,CAAC,EAAE;YAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;YAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;SAAE,GAAG,SAAS,CAAC;QACjF,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC/B,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,EACD,GAAG,EAAE,OAAO,GACX,OAAO,CAAC,eAAe,CAAC,CA4B1B;CACF;AAQD,wBAAgB,aAAa,IAAI,IAAI,CAGpC;AAED,wBAAgB,YAAY,IAAI,SAAS,CAGxC"}
|
|
@@ -2,34 +2,12 @@
|
|
|
2
2
|
* @fileoverview HN API service — Firebase and Algolia HTTP clients with HTML stripping utilities.
|
|
3
3
|
* @module services/hn/hn-service
|
|
4
4
|
*/
|
|
5
|
-
import {
|
|
5
|
+
import { invalidParams, McpError, rateLimited, serviceUnavailable, } from '@cyanheads/mcp-ts-core/errors';
|
|
6
6
|
import { fetchWithTimeout, withRetry } from '@cyanheads/mcp-ts-core/utils';
|
|
7
7
|
import { getServerConfig } from '../../config/server-config.js';
|
|
8
8
|
const HN_API = 'https://hacker-news.firebaseio.com/v0';
|
|
9
9
|
const ALGOLIA_API = 'https://hn.algolia.com/api/v1';
|
|
10
10
|
const REQUEST_TIMEOUT_MS = 10_000;
|
|
11
|
-
/**
|
|
12
|
-
* Project a handler Context onto a RequestContext shape for framework
|
|
13
|
-
* utilities. Runtime-safe — the framework only reads log-binding fields —
|
|
14
|
-
* but RequestContext's `[key: string]: unknown` index signature is not
|
|
15
|
-
* present on Context, so we materialize a plain object whose literal shape
|
|
16
|
-
* satisfies the index signature.
|
|
17
|
-
*/
|
|
18
|
-
function toRequestContext(ctx) {
|
|
19
|
-
const base = {
|
|
20
|
-
requestId: ctx.requestId,
|
|
21
|
-
timestamp: ctx.timestamp,
|
|
22
|
-
};
|
|
23
|
-
if (ctx.tenantId !== undefined)
|
|
24
|
-
base.tenantId = ctx.tenantId;
|
|
25
|
-
if (ctx.traceId !== undefined)
|
|
26
|
-
base.traceId = ctx.traceId;
|
|
27
|
-
if (ctx.spanId !== undefined)
|
|
28
|
-
base.spanId = ctx.spanId;
|
|
29
|
-
if (ctx.auth !== undefined)
|
|
30
|
-
base.auth = ctx.auth;
|
|
31
|
-
return base;
|
|
32
|
-
}
|
|
33
11
|
// ---------------------------------------------------------------------------
|
|
34
12
|
// HTML utilities
|
|
35
13
|
// ---------------------------------------------------------------------------
|
|
@@ -153,26 +131,35 @@ function parseJsonBody(text, upstream) {
|
|
|
153
131
|
* mean "this server broke" and "this server's own fetch timed out". The exact
|
|
154
132
|
* status stays on `data.status`.
|
|
155
133
|
*/
|
|
156
|
-
function upstreamFailureFor(upstream, status) {
|
|
134
|
+
function upstreamFailureFor(upstream, status, cause) {
|
|
157
135
|
if (status === 429) {
|
|
158
|
-
return {
|
|
159
|
-
|
|
136
|
+
return rateLimited(`${upstream} returned HTTP ${status}.`, {
|
|
137
|
+
upstream,
|
|
138
|
+
status,
|
|
160
139
|
reason: 'upstream_rate_limited',
|
|
161
|
-
|
|
162
|
-
|
|
140
|
+
recovery: {
|
|
141
|
+
hint: `${upstream} is rate-limiting this server. Wait several seconds before retrying the same call, and reduce how often it is called.`,
|
|
142
|
+
},
|
|
143
|
+
}, { cause });
|
|
163
144
|
}
|
|
164
145
|
if (status >= 500) {
|
|
165
|
-
return {
|
|
166
|
-
|
|
146
|
+
return serviceUnavailable(`${upstream} returned HTTP ${status}.`, {
|
|
147
|
+
upstream,
|
|
148
|
+
status,
|
|
167
149
|
reason: 'upstream_unavailable',
|
|
168
|
-
|
|
169
|
-
|
|
150
|
+
recovery: {
|
|
151
|
+
hint: `${upstream} is failing or in maintenance. Retry after a short delay — no input change helps while the upstream is down.`,
|
|
152
|
+
},
|
|
153
|
+
}, { cause });
|
|
170
154
|
}
|
|
171
|
-
return {
|
|
172
|
-
|
|
155
|
+
return invalidParams(`${upstream} returned HTTP ${status}.`, {
|
|
156
|
+
upstream,
|
|
157
|
+
status,
|
|
173
158
|
reason: 'upstream_rejected',
|
|
174
|
-
|
|
175
|
-
|
|
159
|
+
recovery: {
|
|
160
|
+
hint: `${upstream} rejected the request as malformed. Check the tool input values against the schema; retrying the same input fails identically.`,
|
|
161
|
+
},
|
|
162
|
+
}, { cause });
|
|
176
163
|
}
|
|
177
164
|
/**
|
|
178
165
|
* Translate `fetchWithTimeout`'s raw non-2xx throw into a classified error
|
|
@@ -196,8 +183,7 @@ async function withUpstreamHttpErrors(upstream, fn) {
|
|
|
196
183
|
const status = err.data.status;
|
|
197
184
|
if (typeof status !== 'number')
|
|
198
185
|
throw err;
|
|
199
|
-
|
|
200
|
-
throw new McpError(code, `${upstream} returned HTTP ${status}.`, { upstream, status, reason, recovery: { hint } }, { cause: err });
|
|
186
|
+
throw upstreamFailureFor(upstream, status, err);
|
|
201
187
|
}
|
|
202
188
|
}
|
|
203
189
|
// ---------------------------------------------------------------------------
|
|
@@ -214,11 +200,12 @@ export class HnService {
|
|
|
214
200
|
* HTML-instead-of-JSON — classified onto a contract reason.
|
|
215
201
|
*/
|
|
216
202
|
getJson(upstream, operation, url, ctx) {
|
|
217
|
-
const rc = toRequestContext(ctx);
|
|
218
203
|
return withUpstreamHttpErrors(upstream, () => withRetry(async () => {
|
|
219
|
-
const res = await fetchWithTimeout(url, REQUEST_TIMEOUT_MS,
|
|
204
|
+
const res = await fetchWithTimeout(url, REQUEST_TIMEOUT_MS, ctx, {
|
|
205
|
+
signal: ctx.signal,
|
|
206
|
+
});
|
|
220
207
|
return parseJsonBody(await res.text(), upstream);
|
|
221
|
-
}, { operation, context:
|
|
208
|
+
}, { operation, context: ctx, signal: ctx.signal }));
|
|
222
209
|
}
|
|
223
210
|
/** Fetch a single item by ID. Returns null when HN reports the item is missing. */
|
|
224
211
|
fetchItem(id, ctx) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hn-service.js","sourceRoot":"","sources":["../../../src/services/hn/hn-service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,
|
|
1
|
+
{"version":3,"file":"hn-service.js","sourceRoot":"","sources":["../../../src/services/hn/hn-service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,aAAa,EACb,QAAQ,EACR,WAAW,EACX,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE3E,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAG5D,MAAM,MAAM,GAAG,uCAAuC,CAAC;AACvD,MAAM,WAAW,GAAG,+BAA+B,CAAC;AACpD,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E,MAAM,aAAa,GAA2B;IAC5C,GAAG,EAAE,GAAG;IACR,EAAE,EAAE,GAAG;IACP,EAAE,EAAE,GAAG;IACP,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;CACV,CAAC;AAEF,8CAA8C;AAC9C,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,IAAI,CAAC,OAAO,CAAC,sCAAsC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE;QACrF,IAAI,GAAG;YAAE,OAAO,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;QACxD,IAAI,GAAG;YAAE,OAAO,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;QACxD,OAAO,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAErB,uBAAuB;IACvB,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,IAAI,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,wCAAwC,EAAE,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE;QACpF,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,UAAU,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,8BAA8B;IAC9B,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAErC,qBAAqB;IACrB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,4CAA4C,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,CACrF,QAAQ,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,KAAK,GAAG,GAAG,CAChD,CAAC;IAEF,2BAA2B;IAC3B,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAEpC,sBAAsB;IACtB,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC,EAAE,CAAS,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAEtF,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IACrB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACvF,OAAO,SAAS,CAAC,MAAM,CAAC;SACrB,OAAO,CAAC,cAAc,EAAE,MAAM,CAAC;SAC/B,OAAO,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;AACvC,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,YAAY,CAAC,GAAmB;IAC9C,OAAO,GAAG,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;AAClC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAuB;IACnD,IAAI,CAAC,GAAG;QAAE,OAAO;IACjB,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;IACT,CAAC;AACH,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,eAAe,CAAC,KAAwB;IACtD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7F,CAAC;AAED,6FAA6F;AAC7F,SAAS,eAAe,CAAC,IAAY;IACnC,OAAO,mCAAmC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CAAI,IAAY,EAAE,QAAgB;IACtD,IAAI,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1B,MAAM,kBAAkB,CAAC,GAAG,QAAQ,uDAAuD,EAAE;YAC3F,QAAQ;YACR,MAAM,EAAE,eAAe;YACvB,QAAQ,EAAE;gBACR,IAAI,EAAE,GAAG,QAAQ,2EAA2E;aAC7F;SACF,CAAC,CAAC;IACL,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAM,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,kBAAkB,CACtB,GAAG,QAAQ,oCAAoC,EAC/C;YACE,QAAQ;YACR,MAAM,EAAE,oBAAoB;YAC5B,QAAQ,EAAE;gBACR,IAAI,EAAE,GAAG,QAAQ,wJAAwJ;aAC1K;SACF,EACD,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAS,kBAAkB,CAAC,QAAgB,EAAE,MAAc,EAAE,KAAe;IAC3E,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;QACnB,OAAO,WAAW,CAChB,GAAG,QAAQ,kBAAkB,MAAM,GAAG,EACtC;YACE,QAAQ;YACR,MAAM;YACN,MAAM,EAAE,uBAAuB;YAC/B,QAAQ,EAAE;gBACR,IAAI,EAAE,GAAG,QAAQ,uHAAuH;aACzI;SACF,EACD,EAAE,KAAK,EAAE,CACV,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;QAClB,OAAO,kBAAkB,CACvB,GAAG,QAAQ,kBAAkB,MAAM,GAAG,EACtC;YACE,QAAQ;YACR,MAAM;YACN,MAAM,EAAE,sBAAsB;YAC9B,QAAQ,EAAE;gBACR,IAAI,EAAE,GAAG,QAAQ,8GAA8G;aAChI;SACF,EACD,EAAE,KAAK,EAAE,CACV,CAAC;IACJ,CAAC;IACD,OAAO,aAAa,CAClB,GAAG,QAAQ,kBAAkB,MAAM,GAAG,EACtC;QACE,QAAQ;QACR,MAAM;QACN,MAAM,EAAE,mBAAmB;QAC3B,QAAQ,EAAE;YACR,IAAI,EAAE,GAAG,QAAQ,gIAAgI;SAClJ;KACF,EACD,EAAE,KAAK,EAAE,CACV,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,KAAK,UAAU,sBAAsB,CAAI,QAAgB,EAAE,EAAoB;IAC7E,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,CAAC,GAAG,YAAY,QAAQ,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,WAAW,KAAK,gBAAgB;YAAE,MAAM,GAAG,CAAC;QACxF,MAAM,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;QAC/B,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,MAAM,GAAG,CAAC;QAE1C,MAAM,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAM,OAAO,SAAS;IACH,gBAAgB,CAAS;IAE1C,YAAY,gBAAwB;QAClC,IAAI,CAAC,gBAAgB,GAAG,gBAAgB,CAAC;IAC3C,CAAC;IAED;;;;OAIG;IACK,OAAO,CACb,QAAgB,EAChB,SAAiB,EACjB,GAAiB,EACjB,GAAY;QAEZ,OAAO,sBAAsB,CAAC,QAAQ,EAAE,GAAG,EAAE,CAC3C,SAAS,CACP,KAAK,IAAI,EAAE;YACT,MAAM,GAAG,GAAG,MAAM,gBAAgB,CAAC,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE;gBAC/D,MAAM,EAAE,GAAG,CAAC,MAAM;aACnB,CAAC,CAAC;YACH,OAAO,aAAa,CAAI,MAAM,GAAG,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;QACtD,CAAC,EACD,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAChD,CACF,CAAC;IACJ,CAAC;IAED,mFAAmF;IACnF,SAAS,CAAC,EAAU,EAAE,GAAY;QAChC,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,SAAS,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IAClF,CAAC;IAED;;;;;OAKG;IACH,SAAS,CAAC,QAAgB,EAAE,GAAY;QACtC,OAAO,IAAI,CAAC,OAAO,CACjB,QAAQ,EACR,cAAc,EACd,GAAG,MAAM,SAAS,kBAAkB,CAAC,QAAQ,CAAC,OAAO,EACrD,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,yEAAyE;IACzE,SAAS,CAAC,IAAgB,EAAE,GAAY;QACtC,MAAM,QAAQ,GAAG,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,SAAS,CAAC;QACnE,OAAO,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,MAAM,IAAI,QAAQ,OAAO,EAAE,GAAG,CAAC,CAAC;IACnF,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,UAAU,CAAC,GAAa,EAAE,GAAY;QAC1C,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAEhC,MAAM,OAAO,GAAG,IAAI,KAAK,CAAgB,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChE,IAAI,IAAI,GAAG,CAAC,CAAC;QAEb,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;YACxB,OAAO,IAAI,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC;gBACzB,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC;gBACjB,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;gBAClB,IAAI,EAAE,IAAI,IAAI;oBAAE,SAAS;gBACzB,IAAI,CAAC;oBACH,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;gBAC7C,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,uCAAuC,EAAE;wBACvD,EAAE;wBACF,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;qBACxD,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QAChE,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;QAC/D,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,uEAAuE;IACvE,MAAM,CACJ,MASC,EACD,GAAY;QAEZ,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,QAAQ,CAAC;QACtE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,WAAW,IAAI,QAAQ,EAAE,CAAC,CAAC;QAElD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1D,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;QAElD,MAAM,QAAQ,GAAa,EAAE,CAAC;QAC9B,IAAI,MAAM,CAAC,IAAI;YAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,MAAM,CAAC,MAAM;YAAE,QAAQ,CAAC,IAAI,CAAC,UAAU,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5D,IAAI,QAAQ,CAAC,MAAM;YAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAEtE,MAAM,cAAc,GAAa,EAAE,CAAC;QACpC,IAAI,MAAM,CAAC,SAAS,IAAI,IAAI;YAAE,cAAc,CAAC,IAAI,CAAC,WAAW,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;QACjF,IAAI,MAAM,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC;YAC5B,cAAc,CAAC,IAAI,CACjB,gBAAgB,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE,CAChF,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC;YAC1B,cAAc,CAAC,IAAI,CACjB,gBAAgB,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE,CAC9E,CAAC;QACJ,CAAC;QACD,IAAI,cAAc,CAAC,MAAM;YAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,gBAAgB,EAAE,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAE5F,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACxD,CAAC;CACF;AAED,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,IAAI,QAA+B,CAAC;AAEpC,MAAM,UAAU,aAAa;IAC3B,MAAM,EAAE,gBAAgB,EAAE,GAAG,eAAe,EAAE,CAAC;IAC/C,QAAQ,GAAG,IAAI,SAAS,CAAC,gBAAgB,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,IAAI,CAAC,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,6DAA6D,CAAC,CAAC;IAC9F,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|