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
@@ -1,74 +0,0 @@
1
- /**
2
- * Markdown cleaner service using Turndown for HTML to Markdown conversion
3
- */
4
- import TurndownService from 'turndown';
5
- const turndown = new TurndownService({
6
- headingStyle: 'atx',
7
- codeBlockStyle: 'fenced',
8
- bulletListMarker: '-',
9
- });
10
- // Remove script, style, nav, footer, aside elements
11
- turndown.remove(['script', 'style', 'nav', 'footer', 'aside', 'noscript']);
12
- /** Maximum HTML content length in characters — prevents event loop blocking on huge pages */
13
- const MAX_CONTENT_LENGTH = 524_288; // 512 * 1024
14
- /**
15
- * Remove HTML comments using linear-time indexOf loop.
16
- * Avoids catastrophic backtracking from /<!--[\s\S]*?-->/g on malformed HTML.
17
- */
18
- function removeHtmlComments(html) {
19
- const parts = [];
20
- let pos = 0;
21
- while (pos < html.length) {
22
- const start = html.indexOf('<!--', pos);
23
- if (start === -1) {
24
- parts.push(html.substring(pos));
25
- break;
26
- }
27
- if (start > pos)
28
- parts.push(html.substring(pos, start));
29
- const end = html.indexOf('-->', start + 4);
30
- if (end === -1) {
31
- parts.push(html.substring(start)); // preserve unclosed comment + rest
32
- break;
33
- }
34
- pos = end + 3;
35
- }
36
- return parts.join('');
37
- }
38
- export class MarkdownCleaner {
39
- /**
40
- * Process HTML content and convert to clean Markdown
41
- * NEVER throws - returns original content on any error for graceful degradation
42
- */
43
- processContent(htmlContent) {
44
- try {
45
- // Handle null/undefined/non-string inputs gracefully
46
- if (!htmlContent || typeof htmlContent !== 'string') {
47
- return htmlContent || '';
48
- }
49
- // If already markdown (no HTML tags), return as-is
50
- if (!htmlContent.includes('<')) {
51
- return htmlContent.trim();
52
- }
53
- // Truncate oversized HTML to prevent blocking the event loop
54
- if (htmlContent.length > MAX_CONTENT_LENGTH) {
55
- htmlContent = htmlContent.substring(0, MAX_CONTENT_LENGTH);
56
- }
57
- // Remove HTML comments before conversion (linear-time)
58
- let content = removeHtmlComments(htmlContent);
59
- // Convert HTML to Markdown using Turndown
60
- content = turndown.turndown(content);
61
- // Clean up whitespace
62
- content = content.replace(/\n{3,}/g, '\n\n');
63
- content = content.trim();
64
- return content;
65
- }
66
- catch (error) {
67
- // Log error but don't crash - return original content for graceful degradation
68
- console.error('[MarkdownCleaner] processContent failed:', error instanceof Error ? error.message : String(error), '| Content length:', htmlContent?.length ?? 0);
69
- // Return original content if conversion fails
70
- return htmlContent || '';
71
- }
72
- }
73
- }
74
- //# sourceMappingURL=markdown-cleaner.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"markdown-cleaner.js","sourceRoot":"","sources":["../../src/services/markdown-cleaner.ts"],"names":[],"mappings":"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"}
@@ -1,16 +0,0 @@
1
- /**
2
- * MCP Tool Definitions
3
- * Generated from YAML configuration for consistency
4
- */
5
- /**
6
- * TOOLS array is now loaded from src/config/yaml/tools.yaml
7
- * This provides a single source of truth for all tool metadata
8
- *
9
- * Benefits:
10
- * - Descriptions defined once in YAML
11
- * - Easy to update without touching TypeScript
12
- * - Consistent format across all tools
13
- * - Validation rules co-located with descriptions
14
- */
15
- export declare const TOOLS: import("../config/types.js").McpTool[];
16
- //# sourceMappingURL=definitions.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;;;;;;;;GASG;AACH,eAAO,MAAM,KAAK,wCAAqB,CAAC"}
@@ -1,17 +0,0 @@
1
- /**
2
- * MCP Tool Definitions
3
- * Generated from YAML configuration for consistency
4
- */
5
- import { generateMcpTools } from '../config/loader.js';
6
- /**
7
- * TOOLS array is now loaded from src/config/yaml/tools.yaml
8
- * This provides a single source of truth for all tool metadata
9
- *
10
- * Benefits:
11
- * - Descriptions defined once in YAML
12
- * - Easy to update without touching TypeScript
13
- * - Consistent format across all tools
14
- * - Validation rules co-located with descriptions
15
- */
16
- export const TOOLS = generateMcpTools();
17
- //# sourceMappingURL=definitions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/tools/definitions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG,gBAAgB,EAAE,CAAC"}
@@ -1,14 +0,0 @@
1
- /**
2
- * Reddit Tools - Search and Fetch
3
- * NEVER throws - always returns structured response for graceful degradation
4
- */
5
- export declare function handleSearchReddit(queries: string[], apiKey: string, dateAfter?: string): Promise<string>;
6
- interface GetRedditPostsOptions {
7
- fetchComments?: boolean;
8
- maxCommentsOverride?: number;
9
- use_llm?: boolean;
10
- what_to_extract?: string;
11
- }
12
- export declare function handleGetRedditPosts(urls: string[], clientId: string, clientSecret: string, maxComments?: number, options?: GetRedditPostsOptions): Promise<string>;
13
- export {};
14
- //# sourceMappingURL=reddit.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"reddit.d.ts","sourceRoot":"","sources":["../../src/tools/reddit.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAqGH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EAAE,EACjB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAMD,UAAU,qBAAqB;IAC7B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AA4MD,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EAAE,EACd,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,WAAW,SAAM,EACjB,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,MAAM,CAAC,CA8BjB"}
@@ -1,265 +0,0 @@
1
- /**
2
- * Reddit Tools - Search and Fetch
3
- * NEVER throws - always returns structured response for graceful degradation
4
- */
5
- import { SearchClient } from '../clients/search.js';
6
- import { RedditClient, calculateCommentAllocation } from '../clients/reddit.js';
7
- import { aggregateAndRankReddit, generateRedditEnhancedOutput } from '../utils/url-aggregator.js';
8
- import { REDDIT } from '../config/index.js';
9
- import { classifyError } from '../utils/errors.js';
10
- import { createLLMProcessor, processContentWithLLM } from '../services/llm-processor.js';
11
- import { pMap } from '../utils/concurrency.js';
12
- import { getToolConfig } from '../config/loader.js';
13
- import { mcpLog, formatSuccess, formatError, formatBatchHeader, TOKEN_BUDGETS, } from './utils.js';
14
- // ============================================================================
15
- // Formatters
16
- // ============================================================================
17
- function formatComments(comments) {
18
- let md = '';
19
- for (const c of comments) {
20
- const indent = ' '.repeat(c.depth);
21
- const op = c.isOP ? ' **[OP]**' : '';
22
- const score = c.score >= 0 ? `+${c.score}` : `${c.score}`;
23
- md += `${indent}- **u/${c.author}**${op} _(${score})_\n`;
24
- const bodyLines = c.body.split('\n').map(line => `${indent} ${line}`).join('\n');
25
- md += `${bodyLines}\n\n`;
26
- }
27
- return md;
28
- }
29
- function formatPost(result, fetchComments) {
30
- const { post, comments, allocatedComments } = result;
31
- let md = `## ${post.title}\n\n`;
32
- md += `**r/${post.subreddit}** • u/${post.author} • ⬆️ ${post.score} • 💬 ${post.commentCount} comments\n`;
33
- md += `🔗 ${post.url}\n\n`;
34
- if (post.body) {
35
- md += `### Post Content\n\n${post.body}\n\n`;
36
- }
37
- if (fetchComments && comments.length > 0) {
38
- md += `### Top Comments (${comments.length}/${post.commentCount} shown, allocated: ${allocatedComments})\n\n`;
39
- md += formatComments(comments);
40
- }
41
- else if (!fetchComments) {
42
- md += `_Comments not fetched (fetch_comments=false)_\n\n`;
43
- }
44
- return md;
45
- }
46
- // ============================================================================
47
- // Search Reddit Handler
48
- // ============================================================================
49
- function countTotalResults(results) {
50
- let total = 0;
51
- for (const items of results.values()) {
52
- total += items.length;
53
- }
54
- return total;
55
- }
56
- function formatNoSearchResults(queryCount) {
57
- return formatError({
58
- code: 'NO_RESULTS',
59
- message: `No results found for any of the ${queryCount} queries`,
60
- toolName: 'search_reddit',
61
- howToFix: [
62
- 'Try broader or simpler search terms',
63
- 'Check spelling of technical terms',
64
- 'Remove date filters if using them',
65
- ],
66
- alternatives: [
67
- 'web_search(keywords=["topic best practices", "topic guide", "topic recommendations 2025"]) — get results from the broader web instead',
68
- 'scrape_links(urls=[...any URLs you already have...], use_llm=true) — if you have URLs from earlier searches, scrape them now',
69
- 'deep_research(questions=[{question: "What are the key findings about [topic]?"}]) — synthesize from AI research',
70
- ],
71
- });
72
- }
73
- function formatSearchRedditError(error) {
74
- const structuredError = classifyError(error);
75
- return formatError({
76
- code: structuredError.code,
77
- message: structuredError.message,
78
- retryable: structuredError.retryable,
79
- toolName: 'search_reddit',
80
- howToFix: ['Verify SERPER_API_KEY is set correctly'],
81
- alternatives: [
82
- 'web_search(keywords=["topic recommendations", "topic best practices", "topic vs alternatives"]) — uses the same API key, but try anyway as it may work for general search',
83
- 'deep_research(questions=[{question: "What does the community recommend for [topic]?"}]) — uses a different API (OpenRouter), not affected by this error',
84
- 'scrape_links(urls=[...any URLs you already have...], use_llm=true) — if you have URLs from prior steps, scrape them now',
85
- ],
86
- });
87
- }
88
- export async function handleSearchReddit(queries, apiKey, dateAfter) {
89
- try {
90
- const limited = queries.slice(0, 50);
91
- const client = new SearchClient(apiKey);
92
- const results = await client.searchRedditMultiple(limited, dateAfter);
93
- const totalResults = countTotalResults(results);
94
- if (totalResults === 0) {
95
- return formatNoSearchResults(limited.length);
96
- }
97
- const aggregation = aggregateAndRankReddit(results, 3);
98
- return generateRedditEnhancedOutput(aggregation, limited, results);
99
- }
100
- catch (error) {
101
- return formatSearchRedditError(error);
102
- }
103
- }
104
- // Get extraction suffix from YAML config (fallback to hardcoded if not found)
105
- function getExtractionSuffix() {
106
- const config = getToolConfig('get_reddit_post');
107
- const suffix = config?.limits?.extraction_suffix;
108
- if (typeof suffix === 'string')
109
- return suffix;
110
- return `
111
- ---
112
-
113
- ⚠️ IMPORTANT: Extract and synthesize the key insights, opinions, and recommendations from these Reddit discussions. Focus on:
114
- - Common themes and consensus across posts
115
- - Specific recommendations with context
116
- - Contrasting viewpoints and debates
117
- - Real-world experiences and lessons learned
118
- - Technical details and implementation tips
119
-
120
- Be comprehensive but concise. Prioritize actionable insights.
121
-
122
- ---`;
123
- }
124
- function enhanceExtractionInstruction(instruction) {
125
- const base = instruction || 'Extract key insights, recommendations, and community consensus from these Reddit discussions.';
126
- return `${base}\n\n${getExtractionSuffix()}`;
127
- }
128
- // --- Helpers ---
129
- function validatePostCount(urlCount) {
130
- if (urlCount < REDDIT.MIN_POSTS) {
131
- return formatError({
132
- code: 'MIN_POSTS',
133
- message: `Minimum ${REDDIT.MIN_POSTS} Reddit posts required. Received: ${urlCount}`,
134
- toolName: 'get_reddit_post',
135
- howToFix: [`Add at least ${REDDIT.MIN_POSTS - urlCount} more Reddit URL(s)`],
136
- alternatives: [
137
- `search_reddit(queries=["topic discussion", "topic recommendations", "topic experiences"]) — find more Reddit posts first, then call get_reddit_post with ${REDDIT.MIN_POSTS}+ URLs`,
138
- ],
139
- });
140
- }
141
- if (urlCount > REDDIT.MAX_POSTS) {
142
- return formatError({
143
- code: 'MAX_POSTS',
144
- message: `Maximum ${REDDIT.MAX_POSTS} Reddit posts allowed. Received: ${urlCount}`,
145
- toolName: 'get_reddit_post',
146
- howToFix: [`Remove ${urlCount - REDDIT.MAX_POSTS} URL(s) and retry`],
147
- });
148
- }
149
- return null;
150
- }
151
- async function applyLlmToPost(postContent, result, url, llmProcessor, enhancedInstruction, tokensPerUrl, index, total) {
152
- mcpLog('info', `[${index}/${total}] Applying LLM extraction to ${url}`, 'reddit');
153
- const llmResult = await processContentWithLLM(postContent, { use_llm: true, what_to_extract: enhancedInstruction, max_tokens: tokensPerUrl }, llmProcessor);
154
- if (llmResult.processed) {
155
- mcpLog('debug', `[${index}/${total}] LLM extraction complete`, 'reddit');
156
- const header = `## LLM Analysis: ${result.post.title}\n\n**r/${result.post.subreddit}** • u/${result.post.author} • ⬆️ ${result.post.score} • 💬 ${result.post.commentCount} comments\n🔗 ${result.post.url}\n\n`;
157
- return { content: header + llmResult.content, llmFailed: false };
158
- }
159
- mcpLog('warning', `[${index}/${total}] LLM extraction failed: ${llmResult.error || 'unknown'}`, 'reddit');
160
- return { content: postContent, llmFailed: true };
161
- }
162
- async function fetchAndProcessPosts(results, urls, fetchComments, use_llm, what_to_extract) {
163
- const llmProcessor = use_llm ? createLLMProcessor() : null;
164
- const tokensPerUrl = use_llm ? Math.floor(TOKEN_BUDGETS.RESEARCH / urls.length) : 0;
165
- const enhancedInstruction = use_llm ? enhanceExtractionInstruction(what_to_extract) : undefined;
166
- let failed = 0;
167
- const failedContents = [];
168
- const successEntries = [];
169
- for (const [url, result] of results) {
170
- if (result instanceof Error) {
171
- failed++;
172
- failedContents.push(`## ❌ Failed: ${url}\n\n_${result.message}_`);
173
- continue;
174
- }
175
- successEntries.push({ url, result, content: formatPost(result, fetchComments) });
176
- }
177
- let llmErrors = 0;
178
- let processedEntries;
179
- if (use_llm && llmProcessor && successEntries.length > 0) {
180
- const llmResults = await pMap(successEntries, async (entry, index) => {
181
- const llmOut = await applyLlmToPost(entry.content, entry.result, entry.url, llmProcessor, enhancedInstruction, tokensPerUrl, index + 1, successEntries.length);
182
- if (llmOut.llmFailed)
183
- llmErrors++;
184
- return { ...entry, content: llmOut.content };
185
- }, 3);
186
- processedEntries = llmResults;
187
- }
188
- else {
189
- processedEntries = successEntries;
190
- }
191
- const contents = [...failedContents, ...processedEntries.map(e => e.content)];
192
- return { successful: successEntries.length, failed, llmErrors, llmAvailable: llmProcessor !== null, contents };
193
- }
194
- function buildRedditStatusExtras(rateLimitHits, use_llm, llmAvailable, llmErrors) {
195
- const extras = [];
196
- if (rateLimitHits > 0)
197
- extras.push(`⚠️ ${rateLimitHits} rate limit retries`);
198
- if (use_llm && !llmAvailable) {
199
- extras.push('⚠️ LLM unavailable (OPENROUTER_API_KEY not set)');
200
- }
201
- else if (llmErrors > 0) {
202
- extras.push(`⚠️ ${llmErrors} LLM extraction failures`);
203
- }
204
- return extras.length > 0 ? `\n${extras.join(' | ')}` : '';
205
- }
206
- function formatRedditOutput(urls, processResult, fetchComments, commentsPerPost, totalBatches, use_llm, tokensPerUrl, extraStatus) {
207
- const batchHeader = formatBatchHeader({
208
- title: `Reddit Posts`,
209
- totalItems: urls.length,
210
- successful: processResult.successful,
211
- failed: processResult.failed,
212
- ...(fetchComments ? { extras: { 'Comments/post': commentsPerPost } } : {}),
213
- ...(use_llm ? { tokensPerItem: tokensPerUrl } : {}),
214
- batches: totalBatches,
215
- });
216
- const nextSteps = [
217
- processResult.successful > 0 ? 'VERIFY CLAIMS: web_search(keywords=["topic claim1 verify", "topic claim2 official docs", "topic best practices"]) — community says X, verify with web' : null,
218
- processResult.successful > 0 ? 'SCRAPE REFERENCED LINKS: scrape_links(urls=[...URLs found in comments...], use_llm=true, what_to_extract="Extract evidence | data | recommendations") — follow external links from discussions' : null,
219
- 'BROADEN: search_reddit(queries=[...related angles...]) — if more perspectives needed',
220
- processResult.successful > 0 ? 'SYNTHESIZE (only after verifying + scraping): deep_research(questions=[{question: "Based on verified Reddit findings about [topic]..."}])' : null,
221
- processResult.failed > 0 ? 'Retry failed URLs individually' : null,
222
- ].filter(Boolean);
223
- return formatSuccess({
224
- title: `Reddit Posts Fetched (${processResult.successful}/${urls.length})`,
225
- summary: batchHeader + extraStatus,
226
- data: processResult.contents.join('\n\n---\n\n'),
227
- nextSteps,
228
- });
229
- }
230
- function formatGetRedditPostsError(error) {
231
- const structuredError = classifyError(error);
232
- return formatError({
233
- code: structuredError.code,
234
- message: structuredError.message,
235
- retryable: structuredError.retryable,
236
- toolName: 'get_reddit_post',
237
- howToFix: ['Verify REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET are set'],
238
- alternatives: [
239
- 'web_search(keywords=["topic reddit discussion", "topic reddit recommendations"]) — search for Reddit content via web search instead',
240
- 'scrape_links(urls=[...the Reddit URLs...], use_llm=true, what_to_extract="Extract post content | top comments | recommendations") — scrape Reddit pages directly as a fallback',
241
- 'deep_research(questions=[{question: "What are community opinions on [topic]?"}]) — get AI-synthesized community perspective',
242
- ],
243
- });
244
- }
245
- export async function handleGetRedditPosts(urls, clientId, clientSecret, maxComments = 100, options = {}) {
246
- try {
247
- const { fetchComments = true, maxCommentsOverride, use_llm = false, what_to_extract } = options;
248
- const validationError = validatePostCount(urls.length);
249
- if (validationError)
250
- return validationError;
251
- const allocation = calculateCommentAllocation(urls.length);
252
- const commentsPerPost = fetchComments ? (maxCommentsOverride || allocation.perPostCapped) : 0;
253
- const totalBatches = Math.ceil(urls.length / REDDIT.BATCH_SIZE);
254
- const client = new RedditClient(clientId, clientSecret);
255
- const batchResult = await client.batchGetPosts(urls, commentsPerPost, fetchComments);
256
- const processResult = await fetchAndProcessPosts(batchResult.results, urls, fetchComments, use_llm, what_to_extract);
257
- const tokensPerUrl = use_llm ? Math.floor(TOKEN_BUDGETS.RESEARCH / urls.length) : 0;
258
- const extraStatus = buildRedditStatusExtras(batchResult.rateLimitHits, use_llm, processResult.llmAvailable, processResult.llmErrors);
259
- return formatRedditOutput(urls, processResult, fetchComments, commentsPerPost, totalBatches, use_llm, tokensPerUrl, extraStatus);
260
- }
261
- catch (error) {
262
- return formatGetRedditPostsError(error);
263
- }
264
- }
265
- //# sourceMappingURL=reddit.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"reddit.js","sourceRoot":"","sources":["../../src/tools/reddit.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,0BAA0B,EAAiC,MAAM,sBAAsB,CAAC;AAC/G,OAAO,EAAE,sBAAsB,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAClG,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EACL,MAAM,EACN,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,aAAa,GACd,MAAM,YAAY,CAAC;AAEpB,+EAA+E;AAC/E,aAAa;AACb,+EAA+E;AAE/E,SAAS,cAAc,CAAC,QAAmB;IACzC,IAAI,EAAE,GAAG,EAAE,CAAC;IACZ,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACpC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC;QAC1D,EAAE,IAAI,GAAG,MAAM,SAAS,CAAC,CAAC,MAAM,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;QACzD,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClF,EAAE,IAAI,GAAG,SAAS,MAAM,CAAC;IAC3B,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,UAAU,CAAC,MAAkB,EAAE,aAAsB;IAC5D,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAAC;IACrD,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,MAAM,CAAC;IAChC,EAAE,IAAI,OAAO,IAAI,CAAC,SAAS,UAAU,IAAI,CAAC,MAAM,SAAS,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,YAAY,aAAa,CAAC;IAC3G,EAAE,IAAI,MAAM,IAAI,CAAC,GAAG,MAAM,CAAC;IAE3B,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,EAAE,IAAI,uBAAuB,IAAI,CAAC,IAAI,MAAM,CAAC;IAC/C,CAAC;IAED,IAAI,aAAa,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,EAAE,IAAI,qBAAqB,QAAQ,CAAC,MAAM,IAAI,IAAI,CAAC,YAAY,sBAAsB,iBAAiB,OAAO,CAAC;QAC9G,EAAE,IAAI,cAAc,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC;SAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC1B,EAAE,IAAI,mDAAmD,CAAC;IAC5D,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,+EAA+E;AAC/E,wBAAwB;AACxB,+EAA+E;AAE/E,SAAS,iBAAiB,CAAC,OAA+B;IACxD,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACrC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC;IACxB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,qBAAqB,CAAC,UAAkB;IAC/C,OAAO,WAAW,CAAC;QACjB,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,mCAAmC,UAAU,UAAU;QAChE,QAAQ,EAAE,eAAe;QACzB,QAAQ,EAAE;YACR,qCAAqC;YACrC,mCAAmC;YACnC,mCAAmC;SACpC;QACD,YAAY,EAAE;YACZ,uIAAuI;YACvI,8HAA8H;YAC9H,iHAAiH;SAClH;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,uBAAuB,CAAC,KAAc;IAC7C,MAAM,eAAe,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAC7C,OAAO,WAAW,CAAC;QACjB,IAAI,EAAE,eAAe,CAAC,IAAI;QAC1B,OAAO,EAAE,eAAe,CAAC,OAAO;QAChC,SAAS,EAAE,eAAe,CAAC,SAAS;QACpC,QAAQ,EAAE,eAAe;QACzB,QAAQ,EAAE,CAAC,wCAAwC,CAAC;QACpD,YAAY,EAAE;YACZ,2KAA2K;YAC3K,yJAAyJ;YACzJ,yHAAyH;SAC1H;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAiB,EACjB,MAAc,EACd,SAAkB;IAElB,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;QACxC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QAEtE,MAAM,YAAY,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,qBAAqB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,WAAW,GAAG,sBAAsB,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACvD,OAAO,4BAA4B,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACrE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,uBAAuB,CAAC,KAAK,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAaD,8EAA8E;AAC9E,SAAS,mBAAmB;IAC1B,MAAM,MAAM,GAAG,aAAa,CAAC,iBAAiB,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,iBAAiB,CAAC;IACjD,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC;IAC9C,OAAO;;;;;;;;;;;;IAYL,CAAC;AACL,CAAC;AAED,SAAS,4BAA4B,CAAC,WAA+B;IACnE,MAAM,IAAI,GAAG,WAAW,IAAI,+FAA+F,CAAC;IAC5H,OAAO,GAAG,IAAI,OAAO,mBAAmB,EAAE,EAAE,CAAC;AAC/C,CAAC;AAYD,kBAAkB;AAElB,SAAS,iBAAiB,CAAC,QAAgB;IACzC,IAAI,QAAQ,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAChC,OAAO,WAAW,CAAC;YACjB,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,WAAW,MAAM,CAAC,SAAS,qCAAqC,QAAQ,EAAE;YACnF,QAAQ,EAAE,iBAAiB;YAC3B,QAAQ,EAAE,CAAC,gBAAgB,MAAM,CAAC,SAAS,GAAG,QAAQ,qBAAqB,CAAC;YAC5E,YAAY,EAAE;gBACZ,4JAA4J,MAAM,CAAC,SAAS,QAAQ;aACrL;SACF,CAAC,CAAC;IACL,CAAC;IACD,IAAI,QAAQ,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAChC,OAAO,WAAW,CAAC;YACjB,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,WAAW,MAAM,CAAC,SAAS,oCAAoC,QAAQ,EAAE;YAClF,QAAQ,EAAE,iBAAiB;YAC3B,QAAQ,EAAE,CAAC,UAAU,QAAQ,GAAG,MAAM,CAAC,SAAS,mBAAmB,CAAC;SACrE,CAAC,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,cAAc,CAC3B,WAAmB,EACnB,MAAkB,EAClB,GAAW,EACX,YAAgE,EAChE,mBAAuC,EACvC,YAAoB,EACpB,KAAa,EACb,KAAa;IAEb,MAAM,CAAC,MAAM,EAAE,IAAI,KAAK,IAAI,KAAK,gCAAgC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;IAElF,MAAM,SAAS,GAAG,MAAM,qBAAqB,CAC3C,WAAW,EACX,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,EAAE,mBAAmB,EAAE,UAAU,EAAE,YAAY,EAAE,EACjF,YAAY,CACb,CAAC;IAEF,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;QACxB,MAAM,CAAC,OAAO,EAAE,IAAI,KAAK,IAAI,KAAK,2BAA2B,EAAE,QAAQ,CAAC,CAAC;QACzE,MAAM,MAAM,GAAG,oBAAoB,MAAM,CAAC,IAAI,CAAC,KAAK,WAAW,MAAM,CAAC,IAAI,CAAC,SAAS,UAAU,MAAM,CAAC,IAAI,CAAC,MAAM,SAAS,MAAM,CAAC,IAAI,CAAC,KAAK,SAAS,MAAM,CAAC,IAAI,CAAC,YAAY,iBAAiB,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;QAClN,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACnE,CAAC;IAED,MAAM,CAAC,SAAS,EAAE,IAAI,KAAK,IAAI,KAAK,4BAA4B,SAAS,CAAC,KAAK,IAAI,SAAS,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC1G,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AACnD,CAAC;AAED,KAAK,UAAU,oBAAoB,CACjC,OAAwC,EACxC,IAAc,EACd,aAAsB,EACtB,OAAgB,EAChB,eAAmC;IAEnC,MAAM,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,kBAAkB,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3D,MAAM,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpF,MAAM,mBAAmB,GAAG,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEhG,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,cAAc,GAAa,EAAE,CAAC;IACpC,MAAM,cAAc,GAA2D,EAAE,CAAC;IAElF,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACpC,IAAI,MAAM,YAAY,KAAK,EAAE,CAAC;YAC5B,MAAM,EAAE,CAAC;YACT,cAAc,CAAC,IAAI,CAAC,gBAAgB,GAAG,QAAQ,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC;YAClE,SAAS;QACX,CAAC;QACD,cAAc,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,MAAM,EAAE,aAAa,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC;IAED,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,gBAAuC,CAAC;IAE5C,IAAI,OAAO,IAAI,YAAY,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;YACnE,MAAM,MAAM,GAAG,MAAM,cAAc,CACjC,KAAK,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,EAAE,YAAY,EAAE,mBAAmB,EACzE,YAAY,EAAE,KAAK,GAAG,CAAC,EAAE,cAAc,CAAC,MAAM,CAC/C,CAAC;YACF,IAAI,MAAM,CAAC,SAAS;gBAAE,SAAS,EAAE,CAAC;YAClC,OAAO,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;QAC/C,CAAC,EAAE,CAAC,CAAC,CAAC;QACN,gBAAgB,GAAG,UAAU,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,gBAAgB,GAAG,cAAc,CAAC;IACpC,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,GAAG,cAAc,EAAE,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAE9E,OAAO,EAAE,UAAU,EAAE,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,YAAY,KAAK,IAAI,EAAE,QAAQ,EAAE,CAAC;AACjH,CAAC;AAED,SAAS,uBAAuB,CAC9B,aAAqB,EACrB,OAAgB,EAChB,YAAqB,EACrB,SAAiB;IAEjB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,aAAa,GAAG,CAAC;QAAE,MAAM,CAAC,IAAI,CAAC,MAAM,aAAa,qBAAqB,CAAC,CAAC;IAC7E,IAAI,OAAO,IAAI,CAAC,YAAY,EAAE,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;IACjE,CAAC;SAAM,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,MAAM,SAAS,0BAA0B,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC5D,CAAC;AAED,SAAS,kBAAkB,CACzB,IAAc,EACd,aAAgC,EAChC,aAAsB,EACtB,eAAuB,EACvB,YAAoB,EACpB,OAAgB,EAChB,YAAoB,EACpB,WAAmB;IAEnB,MAAM,WAAW,GAAG,iBAAiB,CAAC;QACpC,KAAK,EAAE,cAAc;QACrB,UAAU,EAAE,IAAI,CAAC,MAAM;QACvB,UAAU,EAAE,aAAa,CAAC,UAAU;QACpC,MAAM,EAAE,aAAa,CAAC,MAAM;QAC5B,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,eAAe,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnD,OAAO,EAAE,YAAY;KACtB,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG;QAChB,aAAa,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,uJAAuJ,CAAC,CAAC,CAAC,IAAI;QAC7L,aAAa,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,gMAAgM,CAAC,CAAC,CAAC,IAAI;QACtO,sFAAsF;QACtF,aAAa,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,2IAA2I,CAAC,CAAC,CAAC,IAAI;QACjL,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,IAAI;KACnE,CAAC,MAAM,CAAC,OAAO,CAAa,CAAC;IAE9B,OAAO,aAAa,CAAC;QACnB,KAAK,EAAE,yBAAyB,aAAa,CAAC,UAAU,IAAI,IAAI,CAAC,MAAM,GAAG;QAC1E,OAAO,EAAE,WAAW,GAAG,WAAW;QAClC,IAAI,EAAE,aAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC;QAChD,SAAS;KACV,CAAC,CAAC;AACL,CAAC;AAED,SAAS,yBAAyB,CAAC,KAAc;IAC/C,MAAM,eAAe,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;IAC7C,OAAO,WAAW,CAAC;QACjB,IAAI,EAAE,eAAe,CAAC,IAAI;QAC1B,OAAO,EAAE,eAAe,CAAC,OAAO;QAChC,SAAS,EAAE,eAAe,CAAC,SAAS;QACpC,QAAQ,EAAE,iBAAiB;QAC3B,QAAQ,EAAE,CAAC,0DAA0D,CAAC;QACtE,YAAY,EAAE;YACZ,qIAAqI;YACrI,gLAAgL;YAChL,6HAA6H;SAC9H;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAc,EACd,QAAgB,EAChB,YAAoB,EACpB,WAAW,GAAG,GAAG,EACjB,UAAiC,EAAE;IAEnC,IAAI,CAAC;QACH,MAAM,EAAE,aAAa,GAAG,IAAI,EAAE,mBAAmB,EAAE,OAAO,GAAG,KAAK,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC;QAEhG,MAAM,eAAe,GAAG,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACvD,IAAI,eAAe;YAAE,OAAO,eAAe,CAAC;QAE5C,MAAM,UAAU,GAAG,0BAA0B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3D,MAAM,eAAe,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,mBAAmB,IAAI,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9F,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;QAEhE,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QACxD,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,eAAe,EAAE,aAAa,CAAC,CAAC;QAErF,MAAM,aAAa,GAAG,MAAM,oBAAoB,CAC9C,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,eAAe,CACnE,CAAC;QAEF,MAAM,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACpF,MAAM,WAAW,GAAG,uBAAuB,CACzC,WAAW,CAAC,aAAa,EAAE,OAAO,EAAE,aAAa,CAAC,YAAY,EAAE,aAAa,CAAC,SAAS,CACxF,CAAC;QAEF,OAAO,kBAAkB,CACvB,IAAI,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EACnD,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,WAAW,CACjD,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,yBAAyB,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC"}
@@ -1,71 +0,0 @@
1
- /**
2
- * Handler Registry - Central tool registration and execution
3
- * Eliminates repetitive if/else routing with declarative registration
4
- */
5
- import { z } from 'zod';
6
- import { type Capabilities } from '../config/index.js';
7
- /**
8
- * MCP-compliant tool result with index signature for SDK compatibility
9
- */
10
- export interface CallToolResult {
11
- readonly content: Array<{
12
- readonly type: 'text';
13
- readonly text: string;
14
- }>;
15
- readonly isError?: boolean;
16
- [key: string]: unknown;
17
- }
18
- /**
19
- * Configuration for a registered tool
20
- */
21
- export interface ToolRegistration {
22
- readonly name: string;
23
- readonly capability?: keyof Capabilities;
24
- readonly schema: z.ZodSchema;
25
- readonly handler: (params: unknown) => Promise<string>;
26
- readonly postValidate?: (params: unknown) => string | undefined;
27
- readonly transformResponse?: (result: string) => {
28
- content: string;
29
- isError?: boolean;
30
- };
31
- }
32
- /**
33
- * Registry type
34
- */
35
- export type ToolRegistry = Record<string, ToolRegistration>;
36
- /**
37
- * Central registry of all MCP tools
38
- */
39
- export declare const toolRegistry: ToolRegistry;
40
- /**
41
- * Execute a tool by name with full middleware chain
42
- *
43
- * Middleware steps:
44
- * 1. Lookup tool in registry (throw McpError if not found)
45
- * 2. Check capability (return error response if missing)
46
- * 3. Validate params with Zod (return error response if invalid)
47
- * 4. Execute handler (catch and format any errors)
48
- * 5. Transform response if needed
49
- *
50
- * @param name - Tool name from request
51
- * @param args - Raw arguments from request
52
- * @param capabilities - Current capabilities from getCapabilities()
53
- * @returns MCP-compliant tool result
54
- */
55
- export declare function executeTool(name: string, args: unknown, capabilities: Capabilities): Promise<CallToolResult>;
56
- /**
57
- * Get list of all registered tool names
58
- */
59
- export declare function getRegisteredToolNames(): string[];
60
- /**
61
- * Check if a tool is registered
62
- */
63
- export declare function isToolRegistered(name: string): boolean;
64
- /**
65
- * Get tool capabilities for logging
66
- */
67
- export declare function getToolCapabilities(): {
68
- enabled: string[];
69
- disabled: string[];
70
- };
71
- //# sourceMappingURL=registry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAY,MAAM,KAAK,CAAC;AAGlC,OAAO,EAAmD,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAkBxG;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,YAAY,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,MAAM,GAAG,SAAS,CAAC;IAChE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CACzF;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;AAqF5D;;GAEG;AACH,eAAO,MAAM,YAAY,EAAE,YA+C1B,CAAC;AAiEF;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,EACb,YAAY,EAAE,YAAY,GACzB,OAAO,CAAC,cAAc,CAAC,CA4BzB;AAMD;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,CAEjD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,IAAI;IAAE,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAe/E"}