mcp-researchpowerpack 3.9.4 → 4.3.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 (188) hide show
  1. package/README.md +116 -208
  2. package/dist/index.js +280 -337
  3. package/dist/index.js.map +7 -1
  4. package/dist/mcp-use.json +7 -0
  5. package/dist/src/clients/reddit.js +278 -0
  6. package/dist/src/clients/reddit.js.map +7 -0
  7. package/dist/src/clients/scraper.js +326 -0
  8. package/dist/src/clients/scraper.js.map +7 -0
  9. package/dist/src/clients/search.js +217 -0
  10. package/dist/src/clients/search.js.map +7 -0
  11. package/dist/src/config/index.js +138 -0
  12. package/dist/src/config/index.js.map +7 -0
  13. package/dist/src/prompts/deep-research.js +41 -0
  14. package/dist/src/prompts/deep-research.js.map +7 -0
  15. package/dist/src/prompts/reddit-sentiment.js +47 -0
  16. package/dist/src/prompts/reddit-sentiment.js.map +7 -0
  17. package/dist/src/schemas/reddit.js +21 -0
  18. package/dist/src/schemas/reddit.js.map +7 -0
  19. package/dist/src/schemas/scrape-links.js +26 -0
  20. package/dist/src/schemas/scrape-links.js.map +7 -0
  21. package/dist/src/schemas/start-research.js +17 -0
  22. package/dist/src/schemas/start-research.js.map +7 -0
  23. package/dist/src/schemas/web-search.js +53 -0
  24. package/dist/src/schemas/web-search.js.map +7 -0
  25. package/dist/src/services/llm-processor.js +675 -0
  26. package/dist/src/services/llm-processor.js.map +7 -0
  27. package/dist/src/services/markdown-cleaner.js +62 -0
  28. package/dist/src/services/markdown-cleaner.js.map +7 -0
  29. package/dist/src/services/workflow-state.js +116 -0
  30. package/dist/src/services/workflow-state.js.map +7 -0
  31. package/dist/src/tools/mcp-helpers.js +50 -0
  32. package/dist/src/tools/mcp-helpers.js.map +7 -0
  33. package/dist/src/tools/reddit.js +277 -0
  34. package/dist/src/tools/reddit.js.map +7 -0
  35. package/dist/src/tools/registry.js +18 -0
  36. package/dist/src/tools/registry.js.map +7 -0
  37. package/dist/src/tools/scrape.js +334 -0
  38. package/dist/src/tools/scrape.js.map +7 -0
  39. package/dist/src/tools/search.js +423 -0
  40. package/dist/src/tools/search.js.map +7 -0
  41. package/dist/src/tools/start-research.js +199 -0
  42. package/dist/src/tools/start-research.js.map +7 -0
  43. package/dist/src/tools/utils.js +29 -0
  44. package/dist/src/tools/utils.js.map +7 -0
  45. package/dist/src/utils/bootstrap-guard.js +27 -0
  46. package/dist/src/utils/bootstrap-guard.js.map +7 -0
  47. package/dist/src/utils/concurrency.js +62 -0
  48. package/dist/src/utils/concurrency.js.map +7 -0
  49. package/dist/src/utils/content-extractor.js +61 -0
  50. package/dist/src/utils/content-extractor.js.map +7 -0
  51. package/dist/src/utils/errors.js +211 -0
  52. package/dist/src/utils/errors.js.map +7 -0
  53. package/dist/src/utils/logger.js +25 -0
  54. package/dist/src/utils/logger.js.map +7 -0
  55. package/dist/src/utils/markdown-formatter.js +15 -0
  56. package/dist/src/utils/markdown-formatter.js.map +7 -0
  57. package/dist/src/utils/reddit-keyword-guard.js +29 -0
  58. package/dist/src/utils/reddit-keyword-guard.js.map +7 -0
  59. package/dist/src/utils/response.js +81 -0
  60. package/dist/src/utils/response.js.map +7 -0
  61. package/dist/src/utils/retry.js +13 -0
  62. package/dist/src/utils/retry.js.map +7 -0
  63. package/dist/src/utils/sanitize.js +10 -0
  64. package/dist/src/utils/sanitize.js.map +7 -0
  65. package/dist/src/utils/source-type.js +41 -0
  66. package/dist/src/utils/source-type.js.map +7 -0
  67. package/dist/src/utils/url-aggregator.js +227 -0
  68. package/dist/src/utils/url-aggregator.js.map +7 -0
  69. package/dist/src/utils/workflow-key.js +14 -0
  70. package/dist/src/utils/workflow-key.js.map +7 -0
  71. package/dist/src/version.js +32 -0
  72. package/dist/src/version.js.map +7 -0
  73. package/package.json +33 -28
  74. package/dist/clients/reddit.d.ts +0 -69
  75. package/dist/clients/reddit.d.ts.map +0 -1
  76. package/dist/clients/reddit.js +0 -369
  77. package/dist/clients/reddit.js.map +0 -1
  78. package/dist/clients/research.d.ts +0 -67
  79. package/dist/clients/research.d.ts.map +0 -1
  80. package/dist/clients/research.js +0 -290
  81. package/dist/clients/research.js.map +0 -1
  82. package/dist/clients/scraper.d.ts +0 -72
  83. package/dist/clients/scraper.d.ts.map +0 -1
  84. package/dist/clients/scraper.js +0 -338
  85. package/dist/clients/scraper.js.map +0 -1
  86. package/dist/clients/search.d.ts +0 -57
  87. package/dist/clients/search.d.ts.map +0 -1
  88. package/dist/clients/search.js +0 -223
  89. package/dist/clients/search.js.map +0 -1
  90. package/dist/config/index.d.ts +0 -78
  91. package/dist/config/index.d.ts.map +0 -1
  92. package/dist/config/index.js +0 -201
  93. package/dist/config/index.js.map +0 -1
  94. package/dist/config/loader.d.ts +0 -40
  95. package/dist/config/loader.d.ts.map +0 -1
  96. package/dist/config/loader.js +0 -322
  97. package/dist/config/loader.js.map +0 -1
  98. package/dist/config/types.d.ts +0 -81
  99. package/dist/config/types.d.ts.map +0 -1
  100. package/dist/config/types.js +0 -6
  101. package/dist/config/types.js.map +0 -1
  102. package/dist/config/yaml/tools.yaml +0 -146
  103. package/dist/index.d.ts +0 -7
  104. package/dist/index.d.ts.map +0 -1
  105. package/dist/schemas/deep-research.d.ts +0 -64
  106. package/dist/schemas/deep-research.d.ts.map +0 -1
  107. package/dist/schemas/deep-research.js +0 -224
  108. package/dist/schemas/deep-research.js.map +0 -1
  109. package/dist/schemas/scrape-links.d.ts +0 -32
  110. package/dist/schemas/scrape-links.d.ts.map +0 -1
  111. package/dist/schemas/scrape-links.js +0 -34
  112. package/dist/schemas/scrape-links.js.map +0 -1
  113. package/dist/schemas/web-search.d.ts +0 -22
  114. package/dist/schemas/web-search.d.ts.map +0 -1
  115. package/dist/schemas/web-search.js +0 -21
  116. package/dist/schemas/web-search.js.map +0 -1
  117. package/dist/services/file-attachment.d.ts +0 -30
  118. package/dist/services/file-attachment.d.ts.map +0 -1
  119. package/dist/services/file-attachment.js +0 -207
  120. package/dist/services/file-attachment.js.map +0 -1
  121. package/dist/services/llm-processor.d.ts +0 -29
  122. package/dist/services/llm-processor.d.ts.map +0 -1
  123. package/dist/services/llm-processor.js +0 -244
  124. package/dist/services/llm-processor.js.map +0 -1
  125. package/dist/services/markdown-cleaner.d.ts +0 -8
  126. package/dist/services/markdown-cleaner.d.ts.map +0 -1
  127. package/dist/services/markdown-cleaner.js +0 -74
  128. package/dist/services/markdown-cleaner.js.map +0 -1
  129. package/dist/tools/definitions.d.ts +0 -16
  130. package/dist/tools/definitions.d.ts.map +0 -1
  131. package/dist/tools/definitions.js +0 -17
  132. package/dist/tools/definitions.js.map +0 -1
  133. package/dist/tools/reddit.d.ts +0 -14
  134. package/dist/tools/reddit.d.ts.map +0 -1
  135. package/dist/tools/reddit.js +0 -265
  136. package/dist/tools/reddit.js.map +0 -1
  137. package/dist/tools/registry.d.ts +0 -71
  138. package/dist/tools/registry.d.ts.map +0 -1
  139. package/dist/tools/registry.js +0 -252
  140. package/dist/tools/registry.js.map +0 -1
  141. package/dist/tools/research.d.ts +0 -14
  142. package/dist/tools/research.d.ts.map +0 -1
  143. package/dist/tools/research.js +0 -196
  144. package/dist/tools/research.js.map +0 -1
  145. package/dist/tools/scrape.d.ts +0 -14
  146. package/dist/tools/scrape.d.ts.map +0 -1
  147. package/dist/tools/scrape.js +0 -234
  148. package/dist/tools/scrape.js.map +0 -1
  149. package/dist/tools/search.d.ts +0 -10
  150. package/dist/tools/search.d.ts.map +0 -1
  151. package/dist/tools/search.js +0 -158
  152. package/dist/tools/search.js.map +0 -1
  153. package/dist/tools/utils.d.ts +0 -105
  154. package/dist/tools/utils.d.ts.map +0 -1
  155. package/dist/tools/utils.js +0 -159
  156. package/dist/tools/utils.js.map +0 -1
  157. package/dist/utils/concurrency.d.ts +0 -28
  158. package/dist/utils/concurrency.d.ts.map +0 -1
  159. package/dist/utils/concurrency.js +0 -92
  160. package/dist/utils/concurrency.js.map +0 -1
  161. package/dist/utils/errors.d.ts +0 -95
  162. package/dist/utils/errors.d.ts.map +0 -1
  163. package/dist/utils/errors.js +0 -390
  164. package/dist/utils/errors.js.map +0 -1
  165. package/dist/utils/logger.d.ts +0 -39
  166. package/dist/utils/logger.d.ts.map +0 -1
  167. package/dist/utils/logger.js +0 -57
  168. package/dist/utils/logger.js.map +0 -1
  169. package/dist/utils/markdown-formatter.d.ts +0 -5
  170. package/dist/utils/markdown-formatter.d.ts.map +0 -1
  171. package/dist/utils/markdown-formatter.js +0 -15
  172. package/dist/utils/markdown-formatter.js.map +0 -1
  173. package/dist/utils/response.d.ts +0 -93
  174. package/dist/utils/response.d.ts.map +0 -1
  175. package/dist/utils/response.js +0 -170
  176. package/dist/utils/response.js.map +0 -1
  177. package/dist/utils/retry.d.ts +0 -43
  178. package/dist/utils/retry.d.ts.map +0 -1
  179. package/dist/utils/retry.js +0 -57
  180. package/dist/utils/retry.js.map +0 -1
  181. package/dist/utils/url-aggregator.d.ts +0 -90
  182. package/dist/utils/url-aggregator.d.ts.map +0 -1
  183. package/dist/utils/url-aggregator.js +0 -538
  184. package/dist/utils/url-aggregator.js.map +0 -1
  185. package/dist/version.d.ts +0 -29
  186. package/dist/version.d.ts.map +0 -1
  187. package/dist/version.js +0 -55
  188. package/dist/version.js.map +0 -1
@@ -0,0 +1,277 @@
1
+ import {
2
+ getRedditPostParamsSchema,
3
+ getRedditPostOutputSchema
4
+ } from "../schemas/reddit.js";
5
+ import { RedditClient } from "../clients/reddit.js";
6
+ import { REDDIT, getCapabilities, getMissingEnvMessage, parseEnv } from "../config/index.js";
7
+ import { classifyError } from "../utils/errors.js";
8
+ import {
9
+ formatSuccess,
10
+ formatError,
11
+ formatBatchHeader
12
+ } from "./utils.js";
13
+ import {
14
+ createToolReporter,
15
+ NOOP_REPORTER,
16
+ toolFailure,
17
+ toolSuccess,
18
+ toToolResponse
19
+ } from "./mcp-helpers.js";
20
+ import { requireBootstrap } from "../utils/bootstrap-guard.js";
21
+ function countWords(text) {
22
+ const plain = text.replace(/[*_~`#>|[\]()!-]/g, "");
23
+ return plain.split(/\s+/).filter((w) => w.length > 0).length;
24
+ }
25
+ function formatComments(comments, maxWords) {
26
+ let md = "";
27
+ let wordsUsed = 0;
28
+ let shown = 0;
29
+ for (const c of comments) {
30
+ const indent = " ".repeat(c.depth);
31
+ const op = c.isOP ? " **[OP]**" : "";
32
+ const score = c.score >= 0 ? `+${c.score}` : `${c.score}`;
33
+ const authorLine = `${indent}- **u/${c.author}**${op} _(${score})_
34
+ `;
35
+ const bodyLines = c.body.split("\n").map((line) => `${indent} ${line}`).join("\n");
36
+ const commentMd = `${authorLine}${bodyLines}
37
+
38
+ `;
39
+ const commentWords = countWords(commentMd);
40
+ if (wordsUsed + commentWords > maxWords && shown > 0) break;
41
+ md += commentMd;
42
+ wordsUsed += commentWords;
43
+ shown++;
44
+ }
45
+ return { md, wordsUsed, shown, truncated: comments.length - shown };
46
+ }
47
+ function formatPost(result, fetchComments, maxWords) {
48
+ const { post, comments } = result;
49
+ let md = `## ${post.title}
50
+
51
+ `;
52
+ md += `**r/${post.subreddit}** \u2022 u/${post.author} \u2022 \u2B06\uFE0F ${post.score} \u2022 \u{1F4AC} ${post.commentCount} comments
53
+ `;
54
+ md += `\u{1F517} ${post.url}
55
+
56
+ `;
57
+ let wordsUsed = countWords(md);
58
+ if (post.body) {
59
+ const bodySection = `### Post Content
60
+
61
+ ${post.body}
62
+
63
+ `;
64
+ wordsUsed += countWords(bodySection);
65
+ md += bodySection;
66
+ }
67
+ let commentsShown = 0;
68
+ let commentsTruncated = 0;
69
+ if (fetchComments && comments.length > 0) {
70
+ const remainingWords = Math.max(0, maxWords - wordsUsed);
71
+ const commentsResult = formatComments(comments, remainingWords);
72
+ commentsShown = commentsResult.shown;
73
+ commentsTruncated = commentsResult.truncated;
74
+ md += `### Top Comments (${commentsResult.shown}/${post.commentCount} shown, ${commentsResult.wordsUsed.toLocaleString()} words)
75
+
76
+ `;
77
+ md += commentsResult.md;
78
+ wordsUsed += commentsResult.wordsUsed;
79
+ if (commentsResult.truncated > 0) {
80
+ md += `
81
+ _${commentsResult.truncated} more comments not shown (word budget reached)._
82
+
83
+ `;
84
+ }
85
+ }
86
+ return { md, wordsUsed, commentsShown, commentsTruncated };
87
+ }
88
+ function validatePostCount(urlCount) {
89
+ if (urlCount < REDDIT.MIN_POSTS) {
90
+ return formatError({
91
+ code: "MIN_POSTS",
92
+ message: `Minimum ${REDDIT.MIN_POSTS} Reddit posts required. Received: ${urlCount}`,
93
+ toolName: "get-reddit-post",
94
+ howToFix: [`Add at least ${REDDIT.MIN_POSTS - urlCount} more Reddit URL(s)`],
95
+ alternatives: [
96
+ `web-search(queries=["topic discussion", "topic recommendations"], extract="...", scope: "reddit") \u2014 find more Reddit post permalinks first, then call get-reddit-post with ${REDDIT.MIN_POSTS}+ URLs`
97
+ ]
98
+ });
99
+ }
100
+ if (urlCount > REDDIT.MAX_POSTS) {
101
+ return formatError({
102
+ code: "MAX_POSTS",
103
+ message: `Maximum ${REDDIT.MAX_POSTS} Reddit posts allowed. Received: ${urlCount}`,
104
+ toolName: "get-reddit-post",
105
+ howToFix: [`Remove ${urlCount - REDDIT.MAX_POSTS} URL(s) and retry`]
106
+ });
107
+ }
108
+ return null;
109
+ }
110
+ async function fetchAndProcessPosts(results) {
111
+ let failed = 0;
112
+ const failedContents = [];
113
+ const successContents = [];
114
+ let successful = 0;
115
+ let totalWordsUsed = 0;
116
+ const skippedUrls = [];
117
+ for (const [url, result] of results) {
118
+ if (result instanceof Error) {
119
+ failed++;
120
+ failedContents.push(`## \u274C Failed: ${url}
121
+
122
+ _${result.message}_`);
123
+ continue;
124
+ }
125
+ if (totalWordsUsed >= REDDIT.MAX_WORDS_TOTAL) {
126
+ skippedUrls.push(url);
127
+ continue;
128
+ }
129
+ const formatted = formatPost(result, true, REDDIT.MAX_WORDS_PER_POST);
130
+ totalWordsUsed += formatted.wordsUsed;
131
+ successContents.push(formatted.md);
132
+ successful++;
133
+ }
134
+ const contents = [...failedContents, ...successContents];
135
+ return { successful, failed, llmErrors: 0, llmAvailable: false, contents, totalWordsUsed, skippedUrls };
136
+ }
137
+ function buildRedditStatusExtras(rateLimitHits, llmAvailable, llmErrors) {
138
+ const extras = [];
139
+ if (rateLimitHits > 0) extras.push(`\u26A0\uFE0F ${rateLimitHits} rate limit retries`);
140
+ if (!llmAvailable) {
141
+ extras.push("\u26A0\uFE0F LLM unavailable (LLM_EXTRACTION_API_KEY not set) \u2014 raw content returned");
142
+ } else if (llmErrors > 0) {
143
+ extras.push(`\u26A0\uFE0F ${llmErrors} LLM extraction failures`);
144
+ }
145
+ return extras.length > 0 ? `
146
+ ${extras.join(" | ")}` : "";
147
+ }
148
+ function formatRedditOutput(urls, processResult, fetchComments, totalBatches, tokensPerUrl, extraStatus) {
149
+ const batchHeader = formatBatchHeader({
150
+ title: `Reddit Posts`,
151
+ totalItems: urls.length,
152
+ successful: processResult.successful,
153
+ failed: processResult.failed,
154
+ ...fetchComments ? { extras: { "Words used": processResult.totalWordsUsed.toLocaleString() } } : {},
155
+ tokensPerItem: tokensPerUrl,
156
+ batches: totalBatches
157
+ });
158
+ let data = processResult.contents.join("\n\n---\n\n");
159
+ if (processResult.skippedUrls.length > 0) {
160
+ data += "\n\n---\n\n";
161
+ data += `**Word limit reached (${REDDIT.MAX_WORDS_TOTAL.toLocaleString()} words).** The following posts were not included:
162
+ `;
163
+ for (const url of processResult.skippedUrls) {
164
+ data += `- ${url}
165
+ `;
166
+ }
167
+ data += `
168
+ Call get-reddit-post(urls=[...skipped URLs above...]) with just the skipped URLs.`;
169
+ }
170
+ return formatSuccess({
171
+ title: `Reddit Posts Fetched (${processResult.successful}/${urls.length})`,
172
+ summary: batchHeader + extraStatus,
173
+ data
174
+ });
175
+ }
176
+ function formatGetRedditPostsError(error) {
177
+ const structuredError = classifyError(error);
178
+ return formatError({
179
+ code: structuredError.code,
180
+ message: structuredError.message,
181
+ retryable: structuredError.retryable,
182
+ toolName: "get-reddit-post",
183
+ howToFix: ["Verify REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET are set"],
184
+ alternatives: [
185
+ 'web-search(queries=["topic reddit discussion", "topic reddit recommendations"], extract="reddit discussions and recommendations") \u2014 search for Reddit content via web search instead',
186
+ 'scrape-links(urls=[...the Reddit URLs...], extract="post content | top comments | recommendations") \u2014 scrape Reddit pages directly as a fallback'
187
+ ]
188
+ });
189
+ }
190
+ async function handleGetRedditPosts(urls, clientId, clientSecret, reporter = NOOP_REPORTER) {
191
+ const startTime = Date.now();
192
+ try {
193
+ const validationError = validatePostCount(urls.length);
194
+ if (validationError) return toolFailure(validationError);
195
+ const totalBatches = Math.ceil(urls.length / REDDIT.BATCH_SIZE);
196
+ await reporter.log("info", `Fetching ${urls.length} Reddit post(s)`);
197
+ await reporter.progress(20, 100, "Fetching Reddit posts");
198
+ const client = new RedditClient(clientId, clientSecret);
199
+ const batchResult = await client.batchGetPosts(urls, true);
200
+ await reporter.progress(55, 100, "Formatting posts and comments");
201
+ const processResult = await fetchAndProcessPosts(batchResult.results);
202
+ await reporter.progress(85, 100, "Building output");
203
+ const extraStatus = buildRedditStatusExtras(
204
+ batchResult.rateLimitHits,
205
+ false,
206
+ 0
207
+ );
208
+ const content = formatRedditOutput(
209
+ urls,
210
+ processResult,
211
+ true,
212
+ totalBatches,
213
+ 0,
214
+ extraStatus
215
+ );
216
+ const executionTime = Date.now() - startTime;
217
+ if (processResult.successful === 0 && processResult.failed > 0) {
218
+ return toolFailure(content);
219
+ }
220
+ return toolSuccess(content, {
221
+ content,
222
+ metadata: {
223
+ total_items: urls.length,
224
+ successful: processResult.successful,
225
+ failed: processResult.failed,
226
+ execution_time_ms: executionTime,
227
+ rate_limit_hits: batchResult.rateLimitHits
228
+ }
229
+ });
230
+ } catch (error) {
231
+ return toolFailure(formatGetRedditPostsError(error));
232
+ }
233
+ }
234
+ function registerGetRedditPostTool(server) {
235
+ server.tool(
236
+ {
237
+ name: "get-reddit-post",
238
+ title: "Get Reddit Post",
239
+ description: "Fetch up to 100 Reddit posts with full threaded comment trees. Returns the raw post content and all comments with author, score, and OP markers.",
240
+ schema: getRedditPostParamsSchema,
241
+ outputSchema: getRedditPostOutputSchema,
242
+ annotations: {
243
+ readOnlyHint: true,
244
+ idempotentHint: true,
245
+ destructiveHint: false,
246
+ openWorldHint: true,
247
+ // See contract-fixes/03 — non-standard precondition hint.
248
+ ...{ experimental: { requires: ["start-research"] } }
249
+ },
250
+ _meta: { requires: ["start-research"] }
251
+ },
252
+ async ({ urls }, ctx) => {
253
+ if (!getCapabilities().reddit) {
254
+ return toToolResponse(toolFailure(getMissingEnvMessage("reddit")));
255
+ }
256
+ const guard = await requireBootstrap(ctx);
257
+ if (guard) {
258
+ return guard;
259
+ }
260
+ const env = parseEnv();
261
+ const reporter = createToolReporter(ctx, "get-reddit-post");
262
+ const result = await handleGetRedditPosts(
263
+ urls,
264
+ env.REDDIT_CLIENT_ID,
265
+ env.REDDIT_CLIENT_SECRET,
266
+ reporter
267
+ );
268
+ await reporter.progress(100, 100, result.isError ? "Reddit fetch failed" : "Reddit fetch complete");
269
+ return toToolResponse(result);
270
+ }
271
+ );
272
+ }
273
+ export {
274
+ handleGetRedditPosts,
275
+ registerGetRedditPostTool
276
+ };
277
+ //# sourceMappingURL=reddit.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/tools/reddit.ts"],
4
+ "sourcesContent": ["/**\n * Reddit Tools \u2014 get-reddit-post\n *\n * NEVER throws - always returns structured response for graceful degradation.\n *\n * Note: search-reddit was deleted in mcp-revisions/tool-surface/01. Reddit\n * discovery now flows through `web-search` with `scope: \"reddit\"`. See\n * mcp-revisions/tool-surface/04 for the rationale on keeping\n * get-reddit-post separate (Reddit threads have a structurally different\n * response shape than HTML pages).\n */\n\nimport type { MCPServer } from 'mcp-use/server';\n\nimport {\n getRedditPostParamsSchema,\n getRedditPostOutputSchema,\n type GetRedditPostOutput,\n} from '../schemas/reddit.js';\nimport { RedditClient, type PostResult, type Comment } from '../clients/reddit.js';\nimport { REDDIT, getCapabilities, getMissingEnvMessage, parseEnv } from '../config/index.js';\nimport { classifyError } from '../utils/errors.js';\nimport {\n mcpLog,\n formatSuccess,\n formatError,\n formatBatchHeader,\n} from './utils.js';\nimport {\n createToolReporter,\n NOOP_REPORTER,\n toolFailure,\n toolSuccess,\n toToolResponse,\n type ToolExecutionResult,\n type ToolReporter,\n} from './mcp-helpers.js';\nimport { requireBootstrap } from '../utils/bootstrap-guard.js';\n\n// ============================================================================\n// Formatters\n// ============================================================================\n\nfunction countWords(text: string): number {\n const plain = text.replace(/[*_~`#>|[\\]()!-]/g, '');\n return plain.split(/\\s+/).filter(w => w.length > 0).length;\n}\n\ninterface FormattedCommentsResult {\n md: string;\n wordsUsed: number;\n shown: number;\n truncated: number;\n}\n\nfunction formatComments(comments: Comment[], maxWords: number): FormattedCommentsResult {\n let md = '';\n let wordsUsed = 0;\n let shown = 0;\n\n for (const c of comments) {\n const indent = ' '.repeat(c.depth);\n const op = c.isOP ? ' **[OP]**' : '';\n const score = c.score >= 0 ? `+${c.score}` : `${c.score}`;\n const authorLine = `${indent}- **u/${c.author}**${op} _(${score})_\\n`;\n const bodyLines = c.body.split('\\n').map(line => `${indent} ${line}`).join('\\n');\n const commentMd = `${authorLine}${bodyLines}\\n\\n`;\n const commentWords = countWords(commentMd);\n\n if (wordsUsed + commentWords > maxWords && shown > 0) break;\n\n md += commentMd;\n wordsUsed += commentWords;\n shown++;\n }\n\n return { md, wordsUsed, shown, truncated: comments.length - shown };\n}\n\ninterface FormattedPostResult {\n md: string;\n wordsUsed: number;\n commentsShown: number;\n commentsTruncated: number;\n}\n\nfunction formatPost(result: PostResult, fetchComments: boolean, maxWords: number): FormattedPostResult {\n const { post, comments } = result;\n let md = `## ${post.title}\\n\\n`;\n md += `**r/${post.subreddit}** \u2022 u/${post.author} \u2022 \u2B06\uFE0F ${post.score} \u2022 \uD83D\uDCAC ${post.commentCount} comments\\n`;\n md += `\uD83D\uDD17 ${post.url}\\n\\n`;\n\n let wordsUsed = countWords(md);\n\n if (post.body) {\n const bodySection = `### Post Content\\n\\n${post.body}\\n\\n`;\n wordsUsed += countWords(bodySection);\n md += bodySection;\n }\n\n let commentsShown = 0;\n let commentsTruncated = 0;\n\n if (fetchComments && comments.length > 0) {\n const remainingWords = Math.max(0, maxWords - wordsUsed);\n const commentsResult = formatComments(comments, remainingWords);\n commentsShown = commentsResult.shown;\n commentsTruncated = commentsResult.truncated;\n\n md += `### Top Comments (${commentsResult.shown}/${post.commentCount} shown, ${commentsResult.wordsUsed.toLocaleString()} words)\\n\\n`;\n md += commentsResult.md;\n wordsUsed += commentsResult.wordsUsed;\n\n if (commentsResult.truncated > 0) {\n md += `\\n_${commentsResult.truncated} more comments not shown (word budget reached)._\\n\\n`;\n }\n }\n\n return { md, wordsUsed, commentsShown, commentsTruncated };\n}\n\n// ============================================================================\n// Get Reddit Posts Handler\n// ============================================================================\n\n// get-reddit-post no longer uses LLM \u2014 returns raw posts + comments\n\n// --- Internal types ---\n\ninterface PostProcessResult {\n successful: number;\n failed: number;\n llmErrors: number;\n llmAvailable: boolean;\n contents: string[];\n totalWordsUsed: number;\n skippedUrls: string[];\n}\n\n// --- Helpers ---\n\nfunction validatePostCount(urlCount: number): string | null {\n if (urlCount < REDDIT.MIN_POSTS) {\n return formatError({\n code: 'MIN_POSTS',\n message: `Minimum ${REDDIT.MIN_POSTS} Reddit posts required. Received: ${urlCount}`,\n toolName: 'get-reddit-post',\n howToFix: [`Add at least ${REDDIT.MIN_POSTS - urlCount} more Reddit URL(s)`],\n alternatives: [\n `web-search(queries=[\"topic discussion\", \"topic recommendations\"], extract=\"...\", scope: \"reddit\") \u2014 find more Reddit post permalinks first, then call get-reddit-post with ${REDDIT.MIN_POSTS}+ URLs`,\n ],\n });\n }\n if (urlCount > REDDIT.MAX_POSTS) {\n return formatError({\n code: 'MAX_POSTS',\n message: `Maximum ${REDDIT.MAX_POSTS} Reddit posts allowed. Received: ${urlCount}`,\n toolName: 'get-reddit-post',\n howToFix: [`Remove ${urlCount - REDDIT.MAX_POSTS} URL(s) and retry`],\n });\n }\n return null;\n}\n\nasync function fetchAndProcessPosts(\n results: Map<string, PostResult | Error>,\n): Promise<PostProcessResult> {\n let failed = 0;\n const failedContents: string[] = [];\n const successContents: string[] = [];\n let successful = 0;\n let totalWordsUsed = 0;\n const skippedUrls: string[] = [];\n\n for (const [url, result] of results) {\n if (result instanceof Error) {\n failed++;\n failedContents.push(`## \u274C Failed: ${url}\\n\\n_${result.message}_`);\n continue;\n }\n\n if (totalWordsUsed >= REDDIT.MAX_WORDS_TOTAL) {\n skippedUrls.push(url);\n continue;\n }\n\n const formatted = formatPost(result, true, REDDIT.MAX_WORDS_PER_POST);\n totalWordsUsed += formatted.wordsUsed;\n successContents.push(formatted.md);\n successful++;\n }\n\n const contents = [...failedContents, ...successContents];\n return { successful, failed, llmErrors: 0, llmAvailable: false, contents, totalWordsUsed, skippedUrls };\n}\n\nfunction buildRedditStatusExtras(\n rateLimitHits: number,\n llmAvailable: boolean,\n llmErrors: number,\n): string {\n const extras: string[] = [];\n if (rateLimitHits > 0) extras.push(`\u26A0\uFE0F ${rateLimitHits} rate limit retries`);\n if (!llmAvailable) {\n extras.push('\u26A0\uFE0F LLM unavailable (LLM_EXTRACTION_API_KEY not set) \u2014 raw content returned');\n } else if (llmErrors > 0) {\n extras.push(`\u26A0\uFE0F ${llmErrors} LLM extraction failures`);\n }\n return extras.length > 0 ? `\\n${extras.join(' | ')}` : '';\n}\n\nfunction formatRedditOutput(\n urls: string[],\n processResult: PostProcessResult,\n fetchComments: boolean,\n totalBatches: number,\n tokensPerUrl: number,\n extraStatus: string,\n): string {\n const batchHeader = formatBatchHeader({\n title: `Reddit Posts`,\n totalItems: urls.length,\n successful: processResult.successful,\n failed: processResult.failed,\n ...(fetchComments ? { extras: { 'Words used': processResult.totalWordsUsed.toLocaleString() } } : {}),\n tokensPerItem: tokensPerUrl,\n batches: totalBatches,\n });\n\n let data = processResult.contents.join('\\n\\n---\\n\\n');\n\n if (processResult.skippedUrls.length > 0) {\n data += '\\n\\n---\\n\\n';\n data += `**Word limit reached (${REDDIT.MAX_WORDS_TOTAL.toLocaleString()} words).** The following posts were not included:\\n`;\n for (const url of processResult.skippedUrls) {\n data += `- ${url}\\n`;\n }\n data += `\\nCall get-reddit-post(urls=[...skipped URLs above...]) with just the skipped URLs.`;\n }\n\n // No cookie-cutter \"Next Steps\" with literal `[...]` placeholders here\n // either. See: docs/code-review/context/07-derailment-evidence.md\n // ([FOOTER-BAD]) and mcp-revisions/output-shaping/05.\n return formatSuccess({\n title: `Reddit Posts Fetched (${processResult.successful}/${urls.length})`,\n summary: batchHeader + extraStatus,\n data,\n });\n}\n\nfunction formatGetRedditPostsError(error: unknown): string {\n const structuredError = classifyError(error);\n return formatError({\n code: structuredError.code,\n message: structuredError.message,\n retryable: structuredError.retryable,\n toolName: 'get-reddit-post',\n howToFix: ['Verify REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET are set'],\n alternatives: [\n 'web-search(queries=[\"topic reddit discussion\", \"topic reddit recommendations\"], extract=\"reddit discussions and recommendations\") \u2014 search for Reddit content via web search instead',\n 'scrape-links(urls=[...the Reddit URLs...], extract=\"post content | top comments | recommendations\") \u2014 scrape Reddit pages directly as a fallback',\n ],\n });\n}\n\nexport async function handleGetRedditPosts(\n urls: string[],\n clientId: string,\n clientSecret: string,\n reporter: ToolReporter = NOOP_REPORTER,\n): Promise<ToolExecutionResult<GetRedditPostOutput>> {\n const startTime = Date.now();\n try {\n const validationError = validatePostCount(urls.length);\n if (validationError) return toolFailure(validationError);\n\n const totalBatches = Math.ceil(urls.length / REDDIT.BATCH_SIZE);\n\n await reporter.log('info', `Fetching ${urls.length} Reddit post(s)`);\n await reporter.progress(20, 100, 'Fetching Reddit posts');\n const client = new RedditClient(clientId, clientSecret);\n const batchResult = await client.batchGetPosts(urls, true);\n await reporter.progress(55, 100, 'Formatting posts and comments');\n\n const processResult = await fetchAndProcessPosts(batchResult.results);\n await reporter.progress(85, 100, 'Building output');\n\n const extraStatus = buildRedditStatusExtras(\n batchResult.rateLimitHits, false, 0,\n );\n const content = formatRedditOutput(\n urls, processResult, true, totalBatches, 0, extraStatus,\n );\n\n const executionTime = Date.now() - startTime;\n\n // Contract: zero successful posts in a non-empty batch \u2192 isError:true so\n // callers that check response.isError can short-circuit. Partial success\n // still resolves through toolSuccess so the agent sees both rows. See\n // docs/code-review/context/02-current-tool-surface.md (E6).\n if (processResult.successful === 0 && processResult.failed > 0) {\n return toolFailure(content);\n }\n\n return toolSuccess(content, {\n content,\n metadata: {\n total_items: urls.length,\n successful: processResult.successful,\n failed: processResult.failed,\n execution_time_ms: executionTime,\n rate_limit_hits: batchResult.rateLimitHits,\n },\n });\n } catch (error) {\n return toolFailure(formatGetRedditPostsError(error));\n }\n}\n\nexport function registerGetRedditPostTool(server: MCPServer): void {\n server.tool(\n {\n name: 'get-reddit-post',\n title: 'Get Reddit Post',\n description:\n 'Fetch up to 100 Reddit posts with full threaded comment trees. Returns the raw post content and all comments with author, score, and OP markers.',\n schema: getRedditPostParamsSchema,\n outputSchema: getRedditPostOutputSchema,\n annotations: {\n readOnlyHint: true,\n idempotentHint: true,\n destructiveHint: false,\n openWorldHint: true,\n // See contract-fixes/03 \u2014 non-standard precondition hint.\n ...({ experimental: { requires: ['start-research'] } } as Record<string, unknown>),\n },\n _meta: { requires: ['start-research'] },\n },\n async ({ urls }, ctx) => {\n if (!getCapabilities().reddit) {\n return toToolResponse(toolFailure(getMissingEnvMessage('reddit')));\n }\n\n const guard = await requireBootstrap(ctx);\n if (guard) {\n return guard;\n }\n\n const env = parseEnv();\n const reporter = createToolReporter(ctx, 'get-reddit-post');\n const result = await handleGetRedditPosts(\n urls,\n env.REDDIT_CLIENT_ID!,\n env.REDDIT_CLIENT_SECRET!,\n reporter,\n );\n\n await reporter.progress(100, 100, result.isError ? 'Reddit fetch failed' : 'Reddit fetch complete');\n return toToolResponse(result);\n },\n );\n}\n"],
5
+ "mappings": "AAcA;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,SAAS,oBAAmD;AAC5D,SAAS,QAAQ,iBAAiB,sBAAsB,gBAAgB;AACxE,SAAS,qBAAqB;AAC9B;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,wBAAwB;AAMjC,SAAS,WAAW,MAAsB;AACxC,QAAM,QAAQ,KAAK,QAAQ,qBAAqB,EAAE;AAClD,SAAO,MAAM,MAAM,KAAK,EAAE,OAAO,OAAK,EAAE,SAAS,CAAC,EAAE;AACtD;AASA,SAAS,eAAe,UAAqB,UAA2C;AACtF,MAAI,KAAK;AACT,MAAI,YAAY;AAChB,MAAI,QAAQ;AAEZ,aAAW,KAAK,UAAU;AACxB,UAAM,SAAS,KAAK,OAAO,EAAE,KAAK;AAClC,UAAM,KAAK,EAAE,OAAO,cAAc;AAClC,UAAM,QAAQ,EAAE,SAAS,IAAI,IAAI,EAAE,KAAK,KAAK,GAAG,EAAE,KAAK;AACvD,UAAM,aAAa,GAAG,MAAM,SAAS,EAAE,MAAM,KAAK,EAAE,MAAM,KAAK;AAAA;AAC/D,UAAM,YAAY,EAAE,KAAK,MAAM,IAAI,EAAE,IAAI,UAAQ,GAAG,MAAM,KAAK,IAAI,EAAE,EAAE,KAAK,IAAI;AAChF,UAAM,YAAY,GAAG,UAAU,GAAG,SAAS;AAAA;AAAA;AAC3C,UAAM,eAAe,WAAW,SAAS;AAEzC,QAAI,YAAY,eAAe,YAAY,QAAQ,EAAG;AAEtD,UAAM;AACN,iBAAa;AACb;AAAA,EACF;AAEA,SAAO,EAAE,IAAI,WAAW,OAAO,WAAW,SAAS,SAAS,MAAM;AACpE;AASA,SAAS,WAAW,QAAoB,eAAwB,UAAuC;AACrG,QAAM,EAAE,MAAM,SAAS,IAAI;AAC3B,MAAI,KAAK,MAAM,KAAK,KAAK;AAAA;AAAA;AACzB,QAAM,OAAO,KAAK,SAAS,eAAU,KAAK,MAAM,wBAAS,KAAK,KAAK,qBAAS,KAAK,YAAY;AAAA;AAC7F,QAAM,aAAM,KAAK,GAAG;AAAA;AAAA;AAEpB,MAAI,YAAY,WAAW,EAAE;AAE7B,MAAI,KAAK,MAAM;AACb,UAAM,cAAc;AAAA;AAAA,EAAuB,KAAK,IAAI;AAAA;AAAA;AACpD,iBAAa,WAAW,WAAW;AACnC,UAAM;AAAA,EACR;AAEA,MAAI,gBAAgB;AACpB,MAAI,oBAAoB;AAExB,MAAI,iBAAiB,SAAS,SAAS,GAAG;AACxC,UAAM,iBAAiB,KAAK,IAAI,GAAG,WAAW,SAAS;AACvD,UAAM,iBAAiB,eAAe,UAAU,cAAc;AAC9D,oBAAgB,eAAe;AAC/B,wBAAoB,eAAe;AAEnC,UAAM,qBAAqB,eAAe,KAAK,IAAI,KAAK,YAAY,WAAW,eAAe,UAAU,eAAe,CAAC;AAAA;AAAA;AACxH,UAAM,eAAe;AACrB,iBAAa,eAAe;AAE5B,QAAI,eAAe,YAAY,GAAG;AAChC,YAAM;AAAA,GAAM,eAAe,SAAS;AAAA;AAAA;AAAA,IACtC;AAAA,EACF;AAEA,SAAO,EAAE,IAAI,WAAW,eAAe,kBAAkB;AAC3D;AAsBA,SAAS,kBAAkB,UAAiC;AAC1D,MAAI,WAAW,OAAO,WAAW;AAC/B,WAAO,YAAY;AAAA,MACjB,MAAM;AAAA,MACN,SAAS,WAAW,OAAO,SAAS,qCAAqC,QAAQ;AAAA,MACjF,UAAU;AAAA,MACV,UAAU,CAAC,gBAAgB,OAAO,YAAY,QAAQ,qBAAqB;AAAA,MAC3E,cAAc;AAAA,QACZ,mLAA8K,OAAO,SAAS;AAAA,MAChM;AAAA,IACF,CAAC;AAAA,EACH;AACA,MAAI,WAAW,OAAO,WAAW;AAC/B,WAAO,YAAY;AAAA,MACjB,MAAM;AAAA,MACN,SAAS,WAAW,OAAO,SAAS,oCAAoC,QAAQ;AAAA,MAChF,UAAU;AAAA,MACV,UAAU,CAAC,UAAU,WAAW,OAAO,SAAS,mBAAmB;AAAA,IACrE,CAAC;AAAA,EACH;AACA,SAAO;AACT;AAEA,eAAe,qBACb,SAC4B;AAC5B,MAAI,SAAS;AACb,QAAM,iBAA2B,CAAC;AAClC,QAAM,kBAA4B,CAAC;AACnC,MAAI,aAAa;AACjB,MAAI,iBAAiB;AACrB,QAAM,cAAwB,CAAC;AAE/B,aAAW,CAAC,KAAK,MAAM,KAAK,SAAS;AACnC,QAAI,kBAAkB,OAAO;AAC3B;AACA,qBAAe,KAAK,qBAAgB,GAAG;AAAA;AAAA,GAAQ,OAAO,OAAO,GAAG;AAChE;AAAA,IACF;AAEA,QAAI,kBAAkB,OAAO,iBAAiB;AAC5C,kBAAY,KAAK,GAAG;AACpB;AAAA,IACF;AAEA,UAAM,YAAY,WAAW,QAAQ,MAAM,OAAO,kBAAkB;AACpE,sBAAkB,UAAU;AAC5B,oBAAgB,KAAK,UAAU,EAAE;AACjC;AAAA,EACF;AAEA,QAAM,WAAW,CAAC,GAAG,gBAAgB,GAAG,eAAe;AACvD,SAAO,EAAE,YAAY,QAAQ,WAAW,GAAG,cAAc,OAAO,UAAU,gBAAgB,YAAY;AACxG;AAEA,SAAS,wBACP,eACA,cACA,WACQ;AACR,QAAM,SAAmB,CAAC;AAC1B,MAAI,gBAAgB,EAAG,QAAO,KAAK,gBAAM,aAAa,qBAAqB;AAC3E,MAAI,CAAC,cAAc;AACjB,WAAO,KAAK,2FAA4E;AAAA,EAC1F,WAAW,YAAY,GAAG;AACxB,WAAO,KAAK,gBAAM,SAAS,0BAA0B;AAAA,EACvD;AACA,SAAO,OAAO,SAAS,IAAI;AAAA,EAAK,OAAO,KAAK,KAAK,CAAC,KAAK;AACzD;AAEA,SAAS,mBACP,MACA,eACA,eACA,cACA,cACA,aACQ;AACR,QAAM,cAAc,kBAAkB;AAAA,IACpC,OAAO;AAAA,IACP,YAAY,KAAK;AAAA,IACjB,YAAY,cAAc;AAAA,IAC1B,QAAQ,cAAc;AAAA,IACtB,GAAI,gBAAgB,EAAE,QAAQ,EAAE,cAAc,cAAc,eAAe,eAAe,EAAE,EAAE,IAAI,CAAC;AAAA,IACnG,eAAe;AAAA,IACf,SAAS;AAAA,EACX,CAAC;AAED,MAAI,OAAO,cAAc,SAAS,KAAK,aAAa;AAEpD,MAAI,cAAc,YAAY,SAAS,GAAG;AACxC,YAAQ;AACR,YAAQ,yBAAyB,OAAO,gBAAgB,eAAe,CAAC;AAAA;AACxE,eAAW,OAAO,cAAc,aAAa;AAC3C,cAAQ,KAAK,GAAG;AAAA;AAAA,IAClB;AACA,YAAQ;AAAA;AAAA,EACV;AAKA,SAAO,cAAc;AAAA,IACnB,OAAO,yBAAyB,cAAc,UAAU,IAAI,KAAK,MAAM;AAAA,IACvE,SAAS,cAAc;AAAA,IACvB;AAAA,EACF,CAAC;AACH;AAEA,SAAS,0BAA0B,OAAwB;AACzD,QAAM,kBAAkB,cAAc,KAAK;AAC3C,SAAO,YAAY;AAAA,IACjB,MAAM,gBAAgB;AAAA,IACtB,SAAS,gBAAgB;AAAA,IACzB,WAAW,gBAAgB;AAAA,IAC3B,UAAU;AAAA,IACV,UAAU,CAAC,0DAA0D;AAAA,IACrE,cAAc;AAAA,MACZ;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,qBACpB,MACA,UACA,cACA,WAAyB,eAC0B;AACnD,QAAM,YAAY,KAAK,IAAI;AAC3B,MAAI;AACF,UAAM,kBAAkB,kBAAkB,KAAK,MAAM;AACrD,QAAI,gBAAiB,QAAO,YAAY,eAAe;AAEvD,UAAM,eAAe,KAAK,KAAK,KAAK,SAAS,OAAO,UAAU;AAE9D,UAAM,SAAS,IAAI,QAAQ,YAAY,KAAK,MAAM,iBAAiB;AACnE,UAAM,SAAS,SAAS,IAAI,KAAK,uBAAuB;AACxD,UAAM,SAAS,IAAI,aAAa,UAAU,YAAY;AACtD,UAAM,cAAc,MAAM,OAAO,cAAc,MAAM,IAAI;AACzD,UAAM,SAAS,SAAS,IAAI,KAAK,+BAA+B;AAEhE,UAAM,gBAAgB,MAAM,qBAAqB,YAAY,OAAO;AACpE,UAAM,SAAS,SAAS,IAAI,KAAK,iBAAiB;AAElD,UAAM,cAAc;AAAA,MAClB,YAAY;AAAA,MAAe;AAAA,MAAO;AAAA,IACpC;AACA,UAAM,UAAU;AAAA,MACd;AAAA,MAAM;AAAA,MAAe;AAAA,MAAM;AAAA,MAAc;AAAA,MAAG;AAAA,IAC9C;AAEA,UAAM,gBAAgB,KAAK,IAAI,IAAI;AAMnC,QAAI,cAAc,eAAe,KAAK,cAAc,SAAS,GAAG;AAC9D,aAAO,YAAY,OAAO;AAAA,IAC5B;AAEA,WAAO,YAAY,SAAS;AAAA,MAC1B;AAAA,MACA,UAAU;AAAA,QACR,aAAa,KAAK;AAAA,QAClB,YAAY,cAAc;AAAA,QAC1B,QAAQ,cAAc;AAAA,QACtB,mBAAmB;AAAA,QACnB,iBAAiB,YAAY;AAAA,MAC/B;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,WAAO,YAAY,0BAA0B,KAAK,CAAC;AAAA,EACrD;AACF;AAEO,SAAS,0BAA0B,QAAyB;AACjE,SAAO;AAAA,IACL;AAAA,MACE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,aACE;AAAA,MACF,QAAQ;AAAA,MACR,cAAc;AAAA,MACd,aAAa;AAAA,QACX,cAAc;AAAA,QACd,gBAAgB;AAAA,QAChB,iBAAiB;AAAA,QACjB,eAAe;AAAA;AAAA,QAEf,GAAI,EAAE,cAAc,EAAE,UAAU,CAAC,gBAAgB,EAAE,EAAE;AAAA,MACvD;AAAA,MACA,OAAO,EAAE,UAAU,CAAC,gBAAgB,EAAE;AAAA,IACxC;AAAA,IACA,OAAO,EAAE,KAAK,GAAG,QAAQ;AACvB,UAAI,CAAC,gBAAgB,EAAE,QAAQ;AAC7B,eAAO,eAAe,YAAY,qBAAqB,QAAQ,CAAC,CAAC;AAAA,MACnE;AAEA,YAAM,QAAQ,MAAM,iBAAiB,GAAG;AACxC,UAAI,OAAO;AACT,eAAO;AAAA,MACT;AAEA,YAAM,MAAM,SAAS;AACrB,YAAM,WAAW,mBAAmB,KAAK,iBAAiB;AAC1D,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ;AAAA,MACF;AAEA,YAAM,SAAS,SAAS,KAAK,KAAK,OAAO,UAAU,wBAAwB,uBAAuB;AAClG,aAAO,eAAe,MAAM;AAAA,IAC9B;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,18 @@
1
+ import { registerDeepResearchPrompt } from "../prompts/deep-research.js";
2
+ import { registerRedditSentimentPrompt } from "../prompts/reddit-sentiment.js";
3
+ import { registerGetRedditPostTool } from "./reddit.js";
4
+ import { registerScrapeLinksTool } from "./scrape.js";
5
+ import { registerWebSearchTool } from "./search.js";
6
+ import { registerStartResearchTool } from "./start-research.js";
7
+ function registerAllTools(server) {
8
+ registerStartResearchTool(server);
9
+ registerWebSearchTool(server);
10
+ registerGetRedditPostTool(server);
11
+ registerScrapeLinksTool(server);
12
+ registerDeepResearchPrompt(server);
13
+ registerRedditSentimentPrompt(server);
14
+ }
15
+ export {
16
+ registerAllTools
17
+ };
18
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/tools/registry.ts"],
4
+ "sourcesContent": ["import type { MCPServer } from 'mcp-use/server';\n\nimport { registerDeepResearchPrompt } from '../prompts/deep-research.js';\nimport { registerRedditSentimentPrompt } from '../prompts/reddit-sentiment.js';\nimport { registerGetRedditPostTool } from './reddit.js';\nimport { registerScrapeLinksTool } from './scrape.js';\nimport { registerWebSearchTool } from './search.js';\nimport { registerStartResearchTool } from './start-research.js';\n\nexport function registerAllTools(server: MCPServer): void {\n // Tool count is intentionally 4 \u2014 search-reddit was deleted in favor of\n // web-search with `scope: \"reddit\"`. See:\n // docs/code-review/context/02-current-tool-surface.md\n // mcp-revisions/tool-surface/01-delete-search-reddit.md\n // mcp-revisions/tool-surface/02-extend-web-search-with-reddit-scope.md\n registerStartResearchTool(server);\n registerWebSearchTool(server);\n registerGetRedditPostTool(server);\n registerScrapeLinksTool(server);\n registerDeepResearchPrompt(server);\n registerRedditSentimentPrompt(server);\n}\n"],
5
+ "mappings": "AAEA,SAAS,kCAAkC;AAC3C,SAAS,qCAAqC;AAC9C,SAAS,iCAAiC;AAC1C,SAAS,+BAA+B;AACxC,SAAS,6BAA6B;AACtC,SAAS,iCAAiC;AAEnC,SAAS,iBAAiB,QAAyB;AAMxD,4BAA0B,MAAM;AAChC,wBAAsB,MAAM;AAC5B,4BAA0B,MAAM;AAChC,0BAAwB,MAAM;AAC9B,6BAA2B,MAAM;AACjC,gCAA8B,MAAM;AACtC;",
6
+ "names": []
7
+ }