@cyanheads/hn-mcp-server 0.5.21 → 0.6.0

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.
Files changed (44) hide show
  1. package/AGENTS.md +26 -10
  2. package/CLAUDE.md +26 -10
  3. package/Dockerfile +10 -4
  4. package/README.md +31 -19
  5. package/changelog/0.5.x/0.5.22.md +45 -0
  6. package/changelog/0.6.x/0.6.0.md +38 -0
  7. package/dist/index.js +1 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/mcp-server/tools/definitions/get-stories.tool.d.ts.map +1 -1
  10. package/dist/mcp-server/tools/definitions/get-stories.tool.js +31 -17
  11. package/dist/mcp-server/tools/definitions/get-stories.tool.js.map +1 -1
  12. package/dist/mcp-server/tools/definitions/get-thread.tool.d.ts +4 -2
  13. package/dist/mcp-server/tools/definitions/get-thread.tool.d.ts.map +1 -1
  14. package/dist/mcp-server/tools/definitions/get-thread.tool.js +427 -220
  15. package/dist/mcp-server/tools/definitions/get-thread.tool.js.map +1 -1
  16. package/dist/mcp-server/tools/definitions/get-user.tool.d.ts +1 -0
  17. package/dist/mcp-server/tools/definitions/get-user.tool.d.ts.map +1 -1
  18. package/dist/mcp-server/tools/definitions/get-user.tool.js +176 -106
  19. package/dist/mcp-server/tools/definitions/get-user.tool.js.map +1 -1
  20. package/dist/mcp-server/tools/definitions/search-content.tool.d.ts +106 -0
  21. package/dist/mcp-server/tools/definitions/search-content.tool.d.ts.map +1 -1
  22. package/dist/mcp-server/tools/definitions/search-content.tool.js +532 -194
  23. package/dist/mcp-server/tools/definitions/search-content.tool.js.map +1 -1
  24. package/dist/mcp-server/tools/response-budget.d.ts +111 -0
  25. package/dist/mcp-server/tools/response-budget.d.ts.map +1 -0
  26. package/dist/mcp-server/tools/response-budget.js +204 -0
  27. package/dist/mcp-server/tools/response-budget.js.map +1 -0
  28. package/dist/mcp-server/tools/served-at-cap.d.ts +14 -0
  29. package/dist/mcp-server/tools/served-at-cap.d.ts.map +1 -0
  30. package/dist/mcp-server/tools/served-at-cap.js +16 -0
  31. package/dist/mcp-server/tools/served-at-cap.js.map +1 -0
  32. package/dist/mcp-server/tools/thread-cursor.d.ts +68 -0
  33. package/dist/mcp-server/tools/thread-cursor.d.ts.map +1 -0
  34. package/dist/mcp-server/tools/thread-cursor.js +200 -0
  35. package/dist/mcp-server/tools/thread-cursor.js.map +1 -0
  36. package/dist/services/hn/hn-service.d.ts +73 -12
  37. package/dist/services/hn/hn-service.d.ts.map +1 -1
  38. package/dist/services/hn/hn-service.js +127 -38
  39. package/dist/services/hn/hn-service.js.map +1 -1
  40. package/dist/services/hn/types.d.ts +9 -0
  41. package/dist/services/hn/types.d.ts.map +1 -1
  42. package/package.json +13 -12
  43. package/server.json +3 -3
  44. package/skills/hn-guide/SKILL.md +39 -0
@@ -4,6 +4,67 @@
4
4
  */
5
5
  import { z } from '@cyanheads/mcp-ts-core';
6
6
  import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
7
+ /**
8
+ * Drop the scheme and `www.` from a query that is a URL alone. Algolia requires
9
+ * every token, so `https` and `www` would otherwise have to appear in the
10
+ * submitted URL, and the same page submitted under the other scheme or without
11
+ * `www.` would drop out. A query with whitespace is searched as typed, and so
12
+ * is one the prefix would leave empty.
13
+ */
14
+ export declare function stripUrlPrefix(query: string): {
15
+ query: string;
16
+ droppedPrefix?: string;
17
+ };
18
+ /** What the search notice is composed from: the inputs as searched, and the page Algolia returned. */
19
+ export interface SearchNoticeFacts {
20
+ author?: string | undefined;
21
+ /** How a full page over the response budget was fitted to it; absent for a page that fit. */
22
+ budget?: SearchBudget | undefined;
23
+ count: number;
24
+ dateRange?: {
25
+ start?: string | undefined;
26
+ end?: string | undefined;
27
+ } | undefined;
28
+ /** The URL prefix dropped from the caller's query before searching. */
29
+ droppedPrefix?: string | undefined;
30
+ minPoints?: number | undefined;
31
+ /**
32
+ * The caller's count and page when count was above the per-call cap. The
33
+ * search then ran at `count` (the cap) and `page` (the page at the cap where
34
+ * the requested page starts), which the other facts describe.
35
+ */
36
+ overCap?: {
37
+ count: number;
38
+ page: number;
39
+ } | undefined;
40
+ page: number;
41
+ /** The query sent to Algolia; absent for a filter-only search. */
42
+ query?: string | undefined;
43
+ /** Hits on this page. */
44
+ shown: number;
45
+ storyId?: number | undefined;
46
+ tags?: string | undefined;
47
+ totalHits: number;
48
+ /** False when totalHits is an estimate; undefined when Algolia does not say. */
49
+ totalHitsExact?: boolean | undefined;
50
+ totalPages: number;
51
+ }
52
+ /** The two steps that fit a full page over the response budget to it. */
53
+ interface SearchBudget {
54
+ /** Ids of the hits step 2 cut the text of, in page order; empty when step 1 sufficed. */
55
+ cutIds: readonly number[];
56
+ /** Step 1 dropped highlights.text from every hit. False when no hit carried one. */
57
+ highlightsTextOmitted: boolean;
58
+ }
59
+ /**
60
+ * Compose the one `notice` string every search writes. `notice` is last-wins,
61
+ * so each source goes through here: the page-state sentence first, then the
62
+ * cause sentences in input order — query, tags, author, storyId, count — then
63
+ * the budget sentence for a page fitted to the response budget. None replaces
64
+ * another. Undefined when nothing applies — the last page of an uncapped,
65
+ * non-empty search that fit.
66
+ */
67
+ export declare function composeSearchNotice(facts: SearchNoticeFacts): string | undefined;
7
68
  export declare const searchHn: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
8
69
  query: z.ZodOptional<z.ZodString>;
9
70
  tags: z.ZodOptional<z.ZodEnum<{
@@ -35,6 +96,13 @@ export declare const searchHn: import("@cyanheads/mcp-ts-core").ToolDefinition<z
35
96
  }, z.core.$strip>, z.ZodObject<{
36
97
  hits: z.ZodArray<z.ZodObject<{
37
98
  id: z.ZodNumber;
99
+ type: z.ZodOptional<z.ZodEnum<{
100
+ comment: "comment";
101
+ job: "job";
102
+ poll: "poll";
103
+ pollopt: "pollopt";
104
+ story: "story";
105
+ }>>;
38
106
  title: z.ZodOptional<z.ZodString>;
39
107
  url: z.ZodOptional<z.ZodString>;
40
108
  domain: z.ZodOptional<z.ZodString>;
@@ -45,6 +113,7 @@ export declare const searchHn: import("@cyanheads/mcp-ts-core").ToolDefinition<z
45
113
  storyTitle: z.ZodOptional<z.ZodString>;
46
114
  storyId: z.ZodOptional<z.ZodNumber>;
47
115
  text: z.ZodOptional<z.ZodString>;
116
+ textTruncated: z.ZodOptional<z.ZodBoolean>;
48
117
  highlights: z.ZodOptional<z.ZodObject<{
49
118
  title: z.ZodOptional<z.ZodString>;
50
119
  text: z.ZodOptional<z.ZodString>;
@@ -70,6 +139,12 @@ export declare const searchHn: import("@cyanheads/mcp-ts-core").ToolDefinition<z
70
139
  readonly when: "minPoints was combined with tags \"comment\" or \"job\", record types Algolia stores without points.";
71
140
  readonly recovery: "Drop minPoints to search comments or jobs, or search a scored type (story, poll, ask_hn, show_hn, front_page) to filter by points.";
72
141
  readonly severity: "notice";
142
+ }, {
143
+ readonly reason: "count_page_unaligned";
144
+ readonly code: JsonRpcErrorCode.InvalidParams;
145
+ readonly when: "count was above the per-call cap of 50 with a page whose first hit (page × count) begins no page of 50 hits, so the requested page cannot be served from its start at the cap.";
146
+ readonly recovery: "Pass a count of 50 or less with page counted in that count; the error names a count and page that start at the same hit and, when that count is under 25, the page of 50 that holds the hit.";
147
+ readonly severity: "notice";
73
148
  }, {
74
149
  readonly reason: "upstream_rejected";
75
150
  readonly code: JsonRpcErrorCode.InvalidParams;
@@ -105,12 +180,43 @@ export declare const searchHn: import("@cyanheads/mcp-ts-core").ToolDefinition<z
105
180
  readonly retryable: true;
106
181
  readonly thrownBy: "service";
107
182
  }], {
183
+ readonly criteria: z.ZodObject<{
184
+ tags: z.ZodOptional<z.ZodEnum<{
185
+ ask_hn: "ask_hn";
186
+ comment: "comment";
187
+ front_page: "front_page";
188
+ job: "job";
189
+ poll: "poll";
190
+ show_hn: "show_hn";
191
+ story: "story";
192
+ }>>;
193
+ author: z.ZodOptional<z.ZodString>;
194
+ storyId: z.ZodOptional<z.ZodNumber>;
195
+ minPoints: z.ZodOptional<z.ZodNumber>;
196
+ dateRange: z.ZodOptional<z.ZodObject<{
197
+ start: z.ZodOptional<z.ZodString>;
198
+ end: z.ZodOptional<z.ZodString>;
199
+ }, z.core.$strip>>;
200
+ sort: z.ZodEnum<{
201
+ date: "date";
202
+ relevance: "relevance";
203
+ }>;
204
+ count: z.ZodNumber;
205
+ view: z.ZodEnum<{
206
+ compact: "compact";
207
+ full: "full";
208
+ }>;
209
+ }, z.core.$strip>;
108
210
  readonly totalHits: z.ZodNumber;
211
+ readonly totalHitsExact: z.ZodOptional<z.ZodBoolean>;
109
212
  readonly page: z.ZodNumber;
110
213
  readonly totalPages: z.ZodNumber;
214
+ readonly reachableHits: z.ZodOptional<z.ZodNumber>;
111
215
  readonly truncated: z.ZodOptional<z.ZodBoolean>;
112
216
  readonly shown: z.ZodOptional<z.ZodNumber>;
113
217
  readonly cap: z.ZodOptional<z.ZodNumber>;
218
+ readonly highlightsTextOmitted: z.ZodOptional<z.ZodBoolean>;
114
219
  readonly notice: z.ZodOptional<z.ZodString>;
115
220
  }>;
221
+ export {};
116
222
  //# sourceMappingURL=search-content.tool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"search-content.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-content.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AA2KjE,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqYnB,CAAC"}
1
+ {"version":3,"file":"search-content.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/search-content.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AA+HjE;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,CAKvF;AA0ED,sGAAsG;AACtG,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,6FAA6F;IAC7F,MAAM,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,GAAG,SAAS,CAAC;IACjF,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B;;;;OAIG;IACH,OAAO,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,yBAAyB;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,cAAc,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC;CACpB;AA8FD,yEAAyE;AACzE,UAAU,YAAY;IACpB,yFAAyF;IACzF,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1B,oFAAoF;IACpF,qBAAqB,EAAE,OAAO,CAAC;CAChC;AAYD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,GAAG,SAAS,CAOhF;AAmQD,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+XnB,CAAC"}