research-powerpack-mcp 3.5.0 → 3.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +674 -63
- package/dist/clients/reddit.d.ts +6 -1
- package/dist/clients/reddit.d.ts.map +1 -1
- package/dist/clients/reddit.js +60 -24
- package/dist/clients/reddit.js.map +1 -1
- package/dist/clients/scraper.d.ts +6 -1
- package/dist/clients/scraper.d.ts.map +1 -1
- package/dist/clients/scraper.js +77 -38
- package/dist/clients/scraper.js.map +1 -1
- package/dist/clients/search.d.ts +2 -2
- package/dist/clients/search.d.ts.map +1 -1
- package/dist/clients/search.js +11 -6
- package/dist/clients/search.js.map +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +5 -1
- package/dist/config/index.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +6 -1
- package/dist/config/loader.js.map +1 -1
- package/dist/index.js +28 -86
- package/dist/index.js.map +1 -1
- package/dist/schemas/web-search.js +1 -1
- package/dist/schemas/web-search.js.map +1 -1
- package/dist/services/file-attachment.d.ts.map +1 -1
- package/dist/services/file-attachment.js +25 -22
- package/dist/services/file-attachment.js.map +1 -1
- package/dist/tools/reddit.d.ts.map +1 -1
- package/dist/tools/reddit.js +43 -55
- package/dist/tools/reddit.js.map +1 -1
- package/dist/tools/registry.js +2 -2
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/research.d.ts +1 -2
- package/dist/tools/research.d.ts.map +1 -1
- package/dist/tools/research.js +69 -59
- package/dist/tools/research.js.map +1 -1
- package/dist/tools/scrape.d.ts +1 -2
- package/dist/tools/scrape.d.ts.map +1 -1
- package/dist/tools/scrape.js +74 -96
- package/dist/tools/scrape.js.map +1 -1
- package/dist/tools/search.d.ts +1 -2
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +19 -21
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/utils.d.ts +68 -16
- package/dist/tools/utils.d.ts.map +1 -1
- package/dist/tools/utils.js +75 -22
- package/dist/tools/utils.js.map +1 -1
- package/dist/utils/concurrency.d.ts +29 -0
- package/dist/utils/concurrency.d.ts.map +1 -0
- package/dist/utils/concurrency.js +73 -0
- package/dist/utils/concurrency.js.map +1 -0
- package/dist/utils/logger.d.ts +26 -23
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +41 -24
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/response.d.ts +49 -62
- package/dist/utils/response.d.ts.map +1 -1
- package/dist/utils/response.js +102 -134
- package/dist/utils/response.js.map +1 -1
- package/dist/utils/url-aggregator.d.ts.map +1 -1
- package/dist/utils/url-aggregator.js +6 -4
- package/dist/utils/url-aggregator.js.map +1 -1
- package/package.json +2 -8
- package/dist/config/env.d.ts +0 -75
- package/dist/config/env.d.ts.map +0 -1
- package/dist/config/env.js +0 -87
- package/dist/config/env.js.map +0 -1
- package/dist/config/yaml/tools-enhanced.yaml +0 -0
package/dist/tools/scrape.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Scrape Links Tool Handler
|
|
3
3
|
* Implements robust error handling that NEVER crashes the MCP server
|
|
4
4
|
*/
|
|
5
|
-
import pLimit from 'p-limit';
|
|
6
5
|
import { ScraperClient } from '../clients/scraper.js';
|
|
7
6
|
import { MarkdownCleaner } from '../services/markdown-cleaner.js';
|
|
8
7
|
import { createLLMProcessor, processContentWithLLM } from '../services/llm-processor.js';
|
|
@@ -10,7 +9,10 @@ import { removeMetaTags } from '../utils/markdown-formatter.js';
|
|
|
10
9
|
import { SCRAPER } from '../config/index.js';
|
|
11
10
|
import { getToolConfig } from '../config/loader.js';
|
|
12
11
|
import { classifyError } from '../utils/errors.js';
|
|
13
|
-
import {
|
|
12
|
+
import { pMap } from '../utils/concurrency.js';
|
|
13
|
+
import { mcpLog, formatSuccess, formatError, formatBatchHeader, formatDuration, TOKEN_BUDGETS, calculateTokenAllocation, } from './utils.js';
|
|
14
|
+
// Module-level singleton - MarkdownCleaner is stateless
|
|
15
|
+
const markdownCleaner = new MarkdownCleaner();
|
|
14
16
|
// Get extraction suffix from YAML config (fallback to hardcoded if not found)
|
|
15
17
|
function getExtractionSuffix() {
|
|
16
18
|
const config = getToolConfig('scrape_links');
|
|
@@ -24,35 +26,31 @@ function enhanceExtractionInstruction(instruction) {
|
|
|
24
26
|
* Handle scrape links request
|
|
25
27
|
* NEVER throws - always returns a valid response with content and metadata
|
|
26
28
|
*/
|
|
27
|
-
export async function handleScrapeLinks(params
|
|
28
|
-
const { sessionId, logger } = options;
|
|
29
|
+
export async function handleScrapeLinks(params) {
|
|
29
30
|
const startTime = Date.now();
|
|
30
|
-
// Helper to create error response
|
|
31
|
-
const createErrorResponse = (message,
|
|
32
|
-
|
|
33
|
-
const errorContent = formatError({
|
|
31
|
+
// Helper to create error response
|
|
32
|
+
const createErrorResponse = (code, message, retryable = false) => ({
|
|
33
|
+
content: formatError({
|
|
34
34
|
code,
|
|
35
35
|
message,
|
|
36
|
-
retryable
|
|
37
|
-
toolName: '
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
execution_time_ms: executionTime,
|
|
49
|
-
},
|
|
36
|
+
retryable,
|
|
37
|
+
toolName: 'scrape_links',
|
|
38
|
+
howToFix: code === 'NO_URLS' ? ['Provide at least one valid URL'] : undefined,
|
|
39
|
+
}),
|
|
40
|
+
structuredContent: {
|
|
41
|
+
content: message,
|
|
42
|
+
metadata: {
|
|
43
|
+
total_urls: params.urls?.length || 0,
|
|
44
|
+
successful: 0,
|
|
45
|
+
failed: params.urls?.length || 0,
|
|
46
|
+
total_credits: 0,
|
|
47
|
+
execution_time_ms: Date.now() - startTime,
|
|
50
48
|
},
|
|
51
|
-
}
|
|
52
|
-
};
|
|
49
|
+
},
|
|
50
|
+
});
|
|
53
51
|
// Validate params
|
|
54
52
|
if (!params.urls || params.urls.length === 0) {
|
|
55
|
-
return createErrorResponse('No URLs provided'
|
|
53
|
+
return createErrorResponse('NO_URLS', 'No URLs provided');
|
|
56
54
|
}
|
|
57
55
|
// Filter out invalid URLs early
|
|
58
56
|
const validUrls = [];
|
|
@@ -67,11 +65,11 @@ export async function handleScrapeLinks(params, options = {}) {
|
|
|
67
65
|
}
|
|
68
66
|
}
|
|
69
67
|
if (validUrls.length === 0) {
|
|
70
|
-
return createErrorResponse(`All ${params.urls.length} URLs are invalid
|
|
68
|
+
return createErrorResponse('INVALID_URLS', `All ${params.urls.length} URLs are invalid`);
|
|
71
69
|
}
|
|
72
70
|
const tokensPerUrl = calculateTokenAllocation(validUrls.length, TOKEN_BUDGETS.SCRAPER);
|
|
73
71
|
const totalBatches = Math.ceil(validUrls.length / SCRAPER.BATCH_SIZE);
|
|
74
|
-
|
|
72
|
+
mcpLog('info', `Starting scrape: ${validUrls.length} URL(s), ${tokensPerUrl} tokens/URL, ${totalBatches} batch(es)`, 'scrape');
|
|
75
73
|
// Initialize clients safely
|
|
76
74
|
let client;
|
|
77
75
|
try {
|
|
@@ -79,16 +77,15 @@ export async function handleScrapeLinks(params, options = {}) {
|
|
|
79
77
|
}
|
|
80
78
|
catch (error) {
|
|
81
79
|
const err = classifyError(error);
|
|
82
|
-
return createErrorResponse(`Failed to initialize scraper: ${err.message}
|
|
80
|
+
return createErrorResponse('CLIENT_INIT_FAILED', `Failed to initialize scraper: ${err.message}`);
|
|
83
81
|
}
|
|
84
|
-
const markdownCleaner = new MarkdownCleaner();
|
|
85
82
|
const llmProcessor = createLLMProcessor(); // Returns null if not configured
|
|
86
83
|
const enhancedInstruction = params.use_llm
|
|
87
84
|
? enhanceExtractionInstruction(params.what_to_extract)
|
|
88
85
|
: undefined;
|
|
89
86
|
// Scrape URLs - scrapeMultiple NEVER throws
|
|
90
87
|
const results = await client.scrapeMultiple(validUrls, { timeout: params.timeout });
|
|
91
|
-
|
|
88
|
+
mcpLog('info', `Scraping complete. Processing ${results.length} results...`, 'scrape');
|
|
92
89
|
let successful = 0;
|
|
93
90
|
let failed = 0;
|
|
94
91
|
let totalCredits = 0;
|
|
@@ -99,7 +96,7 @@ export async function handleScrapeLinks(params, options = {}) {
|
|
|
99
96
|
failed++;
|
|
100
97
|
contents.push(`## ${invalidUrl}\n\n❌ Invalid URL format`);
|
|
101
98
|
}
|
|
102
|
-
const
|
|
99
|
+
const successItems = [];
|
|
103
100
|
for (let i = 0; i < results.length; i++) {
|
|
104
101
|
const result = results[i];
|
|
105
102
|
if (!result) {
|
|
@@ -107,17 +104,19 @@ export async function handleScrapeLinks(params, options = {}) {
|
|
|
107
104
|
contents.push(`## Unknown URL\n\n❌ No result returned`);
|
|
108
105
|
continue;
|
|
109
106
|
}
|
|
107
|
+
mcpLog('debug', `[${i + 1}/${results.length}] Processing ${result.url}`, 'scrape');
|
|
110
108
|
// Check for errors in result
|
|
111
109
|
if (result.error || result.statusCode < 200 || result.statusCode >= 300) {
|
|
112
110
|
failed++;
|
|
113
111
|
const errorMsg = result.error?.message || result.content || `HTTP ${result.statusCode}`;
|
|
114
112
|
contents.push(`## ${result.url}\n\n❌ Failed to scrape: ${errorMsg}`);
|
|
113
|
+
mcpLog('warning', `[${i + 1}/${results.length}] Failed: ${errorMsg}`, 'scrape');
|
|
115
114
|
continue;
|
|
116
115
|
}
|
|
117
116
|
// Success case
|
|
118
117
|
successful++;
|
|
119
118
|
totalCredits += result.credits;
|
|
120
|
-
// Process content safely
|
|
119
|
+
// Process content safely (CPU-bound, fast)
|
|
121
120
|
let content;
|
|
122
121
|
try {
|
|
123
122
|
content = markdownCleaner.processContent(result.content);
|
|
@@ -125,87 +124,66 @@ export async function handleScrapeLinks(params, options = {}) {
|
|
|
125
124
|
catch {
|
|
126
125
|
content = result.content;
|
|
127
126
|
}
|
|
128
|
-
|
|
127
|
+
successItems.push({ url: result.url, content, index: i });
|
|
129
128
|
}
|
|
130
|
-
//
|
|
131
|
-
if (params.use_llm && llmProcessor &&
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
|
|
135
|
-
const llmResult = await processContentWithLLM(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
if (entry.status === 'fulfilled') {
|
|
140
|
-
const { url, llmResult } = entry.value;
|
|
141
|
-
let content = entry.value.content;
|
|
142
|
-
if (llmResult.processed) {
|
|
143
|
-
content = llmResult.content;
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
llmErrors++;
|
|
147
|
-
}
|
|
148
|
-
try {
|
|
149
|
-
content = removeMetaTags(content);
|
|
150
|
-
}
|
|
151
|
-
catch {
|
|
152
|
-
// If this fails, just use the content as-is
|
|
153
|
-
}
|
|
154
|
-
contents.push(`## ${url}\n\n${content}`);
|
|
155
|
-
}
|
|
156
|
-
else {
|
|
157
|
-
// Safety net — processContentWithLLM never throws, but handle anyway
|
|
158
|
-
llmErrors++;
|
|
159
|
-
// We can't easily recover the URL here, so this is a rare edge case
|
|
160
|
-
contents.push(`## Unknown URL\n\n❌ LLM processing failed unexpectedly`);
|
|
129
|
+
// Pass 2: Parallel LLM extraction for successful results (I/O-bound)
|
|
130
|
+
if (params.use_llm && llmProcessor && successItems.length > 0) {
|
|
131
|
+
mcpLog('info', `Starting parallel LLM extraction for ${successItems.length} pages (concurrency: 3)`, 'scrape');
|
|
132
|
+
const llmResults = await pMap(successItems, async (item) => {
|
|
133
|
+
mcpLog('debug', `LLM extracting ${item.url} (${tokensPerUrl} tokens)...`, 'scrape');
|
|
134
|
+
const llmResult = await processContentWithLLM(item.content, { use_llm: params.use_llm, what_to_extract: enhancedInstruction, max_tokens: tokensPerUrl }, llmProcessor);
|
|
135
|
+
if (llmResult.processed) {
|
|
136
|
+
mcpLog('debug', `LLM extraction complete for ${item.url}`, 'scrape');
|
|
137
|
+
return { ...item, content: llmResult.content };
|
|
161
138
|
}
|
|
139
|
+
llmErrors++;
|
|
140
|
+
mcpLog('warning', `LLM extraction skipped for ${item.url}: ${llmResult.error || 'unknown reason'}`, 'scrape');
|
|
141
|
+
return item; // Graceful degradation — use original cleaned content
|
|
142
|
+
}, 3);
|
|
143
|
+
// Update successItems with LLM-processed content
|
|
144
|
+
for (let i = 0; i < llmResults.length; i++) {
|
|
145
|
+
successItems[i] = llmResults[i];
|
|
162
146
|
}
|
|
163
147
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
content = removeMetaTags(content);
|
|
170
|
-
}
|
|
171
|
-
catch {
|
|
172
|
-
// If this fails, just use the content as-is
|
|
173
|
-
}
|
|
174
|
-
contents.push(`## ${p.url}\n\n${content}`);
|
|
148
|
+
// Pass 3: Final assembly — remove meta tags and build content entries
|
|
149
|
+
for (const item of successItems) {
|
|
150
|
+
let content = item.content;
|
|
151
|
+
try {
|
|
152
|
+
content = removeMetaTags(content);
|
|
175
153
|
}
|
|
154
|
+
catch {
|
|
155
|
+
// If this fails, just use the content as-is
|
|
156
|
+
}
|
|
157
|
+
contents.push(`## ${item.url}\n\n${content}`);
|
|
176
158
|
}
|
|
177
159
|
const executionTime = Date.now() - startTime;
|
|
178
|
-
|
|
179
|
-
// Build response
|
|
180
|
-
const
|
|
181
|
-
title:
|
|
160
|
+
mcpLog('info', `Completed: ${successful} successful, ${failed} failed, ${totalCredits} credits used`, 'scrape');
|
|
161
|
+
// Build 70/20/10 response
|
|
162
|
+
const batchHeader = formatBatchHeader({
|
|
163
|
+
title: `Scraped Content (${params.urls.length} URLs)`,
|
|
182
164
|
totalItems: params.urls.length,
|
|
183
165
|
successful,
|
|
184
166
|
failed,
|
|
185
167
|
tokensPerItem: tokensPerUrl,
|
|
186
|
-
totalBudget: TOKEN_BUDGETS.SCRAPER,
|
|
187
168
|
batches: totalBatches,
|
|
188
|
-
extras:
|
|
169
|
+
extras: {
|
|
170
|
+
'Credits used': totalCredits,
|
|
171
|
+
...(llmErrors > 0 ? { 'LLM extraction failures': llmErrors } : {}),
|
|
172
|
+
},
|
|
189
173
|
});
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
}
|
|
196
|
-
if (failed > 0) {
|
|
197
|
-
nextSteps.push(`Retry failed URLs with increased timeout: \`scrape_links({urls: [...], timeout: 60})\``);
|
|
198
|
-
}
|
|
174
|
+
const nextSteps = [
|
|
175
|
+
successful > 0 ? `Extract specific data: scrape_links(urls=[...], use_llm=true, what_to_extract="Extract pricing | features | testimonials")` : null,
|
|
176
|
+
failed > 0 ? `Retry failed URLs with longer timeout: scrape_links(urls=[...], timeout=60)` : null,
|
|
177
|
+
'Research further: deep_research(questions=[{question: "Based on scraped content..."}])',
|
|
178
|
+
].filter(Boolean);
|
|
199
179
|
const formattedContent = formatSuccess({
|
|
200
|
-
title:
|
|
201
|
-
summary:
|
|
180
|
+
title: 'Scraping Complete',
|
|
181
|
+
summary: batchHeader,
|
|
202
182
|
data: contents.join('\n\n---\n\n'),
|
|
203
183
|
nextSteps,
|
|
204
184
|
metadata: {
|
|
205
|
-
'
|
|
206
|
-
'
|
|
207
|
-
'Failed': failed,
|
|
208
|
-
'Tokens/URL': tokensPerUrl,
|
|
185
|
+
'Execution time': formatDuration(executionTime),
|
|
186
|
+
'Token budget': TOKEN_BUDGETS.SCRAPER.toLocaleString(),
|
|
209
187
|
},
|
|
210
188
|
});
|
|
211
189
|
const metadata = {
|
package/dist/tools/scrape.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scrape.js","sourceRoot":"","sources":["../../src/tools/scrape.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"scrape.js","sourceRoot":"","sources":["../../src/tools/scrape.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/search.d.ts
CHANGED
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
* NEVER throws - always returns structured response for graceful degradation
|
|
4
4
|
*/
|
|
5
5
|
import type { WebSearchParams, WebSearchOutput } from '../schemas/web-search.js';
|
|
6
|
-
|
|
7
|
-
export declare function handleWebSearch(params: WebSearchParams, options?: ToolOptions): Promise<{
|
|
6
|
+
export declare function handleWebSearch(params: WebSearchParams): Promise<{
|
|
8
7
|
content: string;
|
|
9
8
|
structuredContent: WebSearchOutput;
|
|
10
9
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAyBjF,wBAAsB,eAAe,CACnC,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,eAAe,CAAA;CAAE,CAAC,CA2JlE"}
|
package/dist/tools/search.js
CHANGED
|
@@ -6,18 +6,17 @@ import { SearchClient } from '../clients/search.js';
|
|
|
6
6
|
import { aggregateAndRank, buildUrlLookup, lookupUrl, generateEnhancedOutput, markConsensus, } from '../utils/url-aggregator.js';
|
|
7
7
|
import { CTR_WEIGHTS } from '../config/index.js';
|
|
8
8
|
import { classifyError } from '../utils/errors.js';
|
|
9
|
-
import {
|
|
9
|
+
import { mcpLog, formatError, formatDuration, } from './utils.js';
|
|
10
10
|
function getPositionScore(position) {
|
|
11
11
|
if (position >= 1 && position <= 10) {
|
|
12
12
|
return CTR_WEIGHTS[position] ?? 0;
|
|
13
13
|
}
|
|
14
14
|
return Math.max(0, 10 - (position - 10) * 0.5);
|
|
15
15
|
}
|
|
16
|
-
export async function handleWebSearch(params
|
|
17
|
-
const { sessionId, logger } = options;
|
|
16
|
+
export async function handleWebSearch(params) {
|
|
18
17
|
const startTime = Date.now();
|
|
19
18
|
try {
|
|
20
|
-
|
|
19
|
+
mcpLog('info', `Searching for ${params.keywords.length} keyword(s)`, 'search');
|
|
21
20
|
const client = new SearchClient();
|
|
22
21
|
const response = await client.searchMultiple(params.keywords);
|
|
23
22
|
const aggregation = aggregateAndRank(response.searches, 5);
|
|
@@ -86,19 +85,16 @@ export async function handleWebSearch(params, options = {}) {
|
|
|
86
85
|
markdown += `\n---\n\n> *${queriesOmitted} additional queries not shown. Consensus URLs above include all ${response.searches.length} queries.*\n`;
|
|
87
86
|
}
|
|
88
87
|
const executionTime = Date.now() - startTime;
|
|
89
|
-
|
|
90
|
-
// Add
|
|
88
|
+
mcpLog('info', `Search completed: ${totalResults} results, ${aggregation.totalUniqueUrls} unique URLs, ${consensusUrls.length} consensus`, 'search');
|
|
89
|
+
// Add Next Steps section
|
|
91
90
|
const nextSteps = [
|
|
92
|
-
`Scrape top URLs:
|
|
93
|
-
'
|
|
94
|
-
'
|
|
95
|
-
];
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
data: markdown,
|
|
100
|
-
nextSteps,
|
|
101
|
-
});
|
|
91
|
+
consensusUrls.length > 0 ? `Scrape top consensus URLs: scrape_links(urls=[${consensusUrls.slice(0, 3).map(u => `"${u.url}"`).join(', ')}], use_llm=true)` : null,
|
|
92
|
+
'Get Reddit perspective: search_reddit(queries=[...related terms...])',
|
|
93
|
+
'Deep research: deep_research(questions=[{question: "Based on search results..."}])',
|
|
94
|
+
].filter(Boolean);
|
|
95
|
+
markdown += '\n\n---\n\n**Next Steps:**\n';
|
|
96
|
+
nextSteps.forEach(step => { markdown += `→ ${step}\n`; });
|
|
97
|
+
markdown += `\n---\n*${formatDuration(executionTime)} | ${aggregation.totalUniqueUrls} unique URLs | ${consensusUrls.length} consensus*`;
|
|
102
98
|
const metadata = {
|
|
103
99
|
total_keywords: response.totalKeywords,
|
|
104
100
|
total_results: totalResults,
|
|
@@ -107,20 +103,22 @@ export async function handleWebSearch(params, options = {}) {
|
|
|
107
103
|
consensus_url_count: consensusUrls.length,
|
|
108
104
|
frequency_threshold: aggregation.frequencyThreshold,
|
|
109
105
|
};
|
|
110
|
-
return { content:
|
|
106
|
+
return { content: markdown, structuredContent: { content: markdown, metadata } };
|
|
111
107
|
}
|
|
112
108
|
catch (error) {
|
|
113
|
-
// Classify error for better reporting
|
|
114
109
|
const structuredError = classifyError(error);
|
|
115
|
-
await safeLog(logger, sessionId, 'error', `web_search: ${structuredError.message}`, 'WebSearch');
|
|
116
110
|
const executionTime = Date.now() - startTime;
|
|
111
|
+
mcpLog('error', `web_search: ${structuredError.message}`, 'search');
|
|
117
112
|
const errorContent = formatError({
|
|
118
113
|
code: structuredError.code,
|
|
119
114
|
message: structuredError.message,
|
|
120
115
|
retryable: structuredError.retryable,
|
|
121
116
|
toolName: 'web_search',
|
|
122
|
-
howToFix: ['
|
|
123
|
-
alternatives: [
|
|
117
|
+
howToFix: ['Verify SERPER_API_KEY is set correctly'],
|
|
118
|
+
alternatives: [
|
|
119
|
+
'search_reddit(queries=[...]) for Reddit-specific results',
|
|
120
|
+
'deep_research(questions=[...]) for AI-synthesized research',
|
|
121
|
+
],
|
|
124
122
|
});
|
|
125
123
|
return {
|
|
126
124
|
content: errorContent,
|
package/dist/tools/search.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,SAAS,EACT,sBAAsB,EACtB,aAAa,GACd,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/utils.d.ts
CHANGED
|
@@ -1,53 +1,105 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared Tool Utilities
|
|
3
|
-
*
|
|
4
|
-
* Re-exports from specialized utility modules for backwards compatibility
|
|
3
|
+
* Extracted from individual handlers to eliminate duplication
|
|
5
4
|
*/
|
|
6
|
-
export { safeLog, createToolLogger, type
|
|
7
|
-
export { formatSuccess, formatError, formatBatchHeader, formatList,
|
|
5
|
+
export { mcpLog, safeLog as safeLogSimple, createToolLogger, type LogLevel, type ToolLogger as SimpleToolLogger, } from '../utils/logger.js';
|
|
6
|
+
export { formatSuccess, formatError, formatBatchHeader, formatList, formatDuration, truncateText, type SuccessOptions, type ErrorOptions, type BatchHeaderOptions, type ListItem, } from '../utils/response.js';
|
|
8
7
|
/**
|
|
9
|
-
*
|
|
10
|
-
* Centralized here to ensure consistency
|
|
8
|
+
* Centralized token budgets for all tools
|
|
11
9
|
*/
|
|
12
10
|
export declare const TOKEN_BUDGETS: {
|
|
13
|
-
/**
|
|
11
|
+
/** Deep research total budget */
|
|
14
12
|
readonly RESEARCH: 32000;
|
|
15
|
-
/**
|
|
13
|
+
/** Web scraper total budget */
|
|
16
14
|
readonly SCRAPER: 32000;
|
|
17
|
-
/**
|
|
18
|
-
readonly
|
|
15
|
+
/** Reddit comment budget per batch */
|
|
16
|
+
readonly REDDIT_COMMENTS: 1000;
|
|
19
17
|
};
|
|
18
|
+
/**
|
|
19
|
+
* Logger function type used by tools
|
|
20
|
+
*/
|
|
21
|
+
export type ToolLogger = (level: 'info' | 'error' | 'debug', message: string, sessionId: string) => Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Standard tool options passed to handlers
|
|
24
|
+
*/
|
|
25
|
+
export interface ToolOptions {
|
|
26
|
+
sessionId?: string;
|
|
27
|
+
logger?: ToolLogger;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Safe logger wrapper - NEVER throws
|
|
31
|
+
* Logs to provided logger or falls back to console.error
|
|
32
|
+
*
|
|
33
|
+
* @param logger - Optional logger function
|
|
34
|
+
* @param sessionId - Session ID for logging context
|
|
35
|
+
* @param level - Log level
|
|
36
|
+
* @param message - Message to log
|
|
37
|
+
* @param toolName - Name of the tool for prefixing
|
|
38
|
+
*/
|
|
39
|
+
export declare function safeLog(logger: ToolLogger | undefined, sessionId: string | undefined, level: 'info' | 'error' | 'debug', message: string, toolName: string): Promise<void>;
|
|
20
40
|
/**
|
|
21
41
|
* Calculate token allocation for batch operations
|
|
22
42
|
* Distributes a fixed budget across multiple items
|
|
23
43
|
*
|
|
24
44
|
* @param count - Number of items to distribute budget across
|
|
25
|
-
* @param budget - Total token budget
|
|
45
|
+
* @param budget - Total token budget
|
|
26
46
|
* @returns Tokens per item
|
|
27
47
|
*/
|
|
28
|
-
export declare function calculateTokenAllocation(count: number, budget
|
|
48
|
+
export declare function calculateTokenAllocation(count: number, budget: number): number;
|
|
29
49
|
/**
|
|
30
|
-
*
|
|
50
|
+
* Format retry hint based on error retryability
|
|
51
|
+
*
|
|
52
|
+
* @param retryable - Whether the error is retryable
|
|
53
|
+
* @returns Hint string or empty string
|
|
31
54
|
*/
|
|
32
55
|
export declare function formatRetryHint(retryable: boolean): string;
|
|
33
56
|
/**
|
|
34
|
-
*
|
|
57
|
+
* Create a standard error markdown response
|
|
58
|
+
*
|
|
59
|
+
* @param toolName - Name of the tool that errored
|
|
60
|
+
* @param errorCode - Error code
|
|
61
|
+
* @param message - Error message
|
|
62
|
+
* @param retryable - Whether error is retryable
|
|
63
|
+
* @param tip - Optional tip for resolution
|
|
64
|
+
* @returns Formatted markdown error string
|
|
35
65
|
*/
|
|
36
66
|
export declare function formatToolError(toolName: string, errorCode: string, message: string, retryable: boolean, tip?: string): string;
|
|
37
67
|
/**
|
|
38
68
|
* Validate that a value is a non-empty array
|
|
69
|
+
*
|
|
70
|
+
* @param value - Value to check
|
|
71
|
+
* @param fieldName - Field name for error message
|
|
72
|
+
* @returns Error message or undefined if valid
|
|
39
73
|
*/
|
|
40
74
|
export declare function validateNonEmptyArray(value: unknown, fieldName: string): string | undefined;
|
|
41
75
|
/**
|
|
42
76
|
* Validate array length is within bounds
|
|
77
|
+
*
|
|
78
|
+
* @param arr - Array to check
|
|
79
|
+
* @param min - Minimum length
|
|
80
|
+
* @param max - Maximum length
|
|
81
|
+
* @param fieldName - Field name for error message
|
|
82
|
+
* @returns Error message or undefined if valid
|
|
43
83
|
*/
|
|
44
84
|
export declare function validateArrayBounds(arr: unknown[], min: number, max: number, fieldName: string): string | undefined;
|
|
45
85
|
/**
|
|
46
|
-
*
|
|
86
|
+
* Build standard header for batch operation results
|
|
87
|
+
*
|
|
88
|
+
* @param title - Title of the results section
|
|
89
|
+
* @param count - Number of items processed
|
|
90
|
+
* @param tokensPerItem - Tokens allocated per item
|
|
91
|
+
* @param totalBudget - Total token budget
|
|
92
|
+
* @returns Formatted header string
|
|
47
93
|
*/
|
|
48
94
|
export declare function buildBatchHeader(title: string, count: number, tokensPerItem: number, totalBudget: number): string;
|
|
49
95
|
/**
|
|
50
|
-
*
|
|
96
|
+
* Build status line for batch results
|
|
97
|
+
*
|
|
98
|
+
* @param successful - Number of successful items
|
|
99
|
+
* @param failed - Number of failed items
|
|
100
|
+
* @param batches - Number of batches processed
|
|
101
|
+
* @param extras - Optional extra status items
|
|
102
|
+
* @returns Formatted status line
|
|
51
103
|
*/
|
|
52
104
|
export declare function buildStatusLine(successful: number, failed: number, batches: number, extras?: string[]): string;
|
|
53
105
|
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/tools/utils.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/tools/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACL,MAAM,EACN,OAAO,IAAI,aAAa,EACxB,gBAAgB,EAChB,KAAK,QAAQ,EACb,KAAK,UAAU,IAAI,gBAAgB,GACpC,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EACL,aAAa,EACb,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,QAAQ,GACd,MAAM,sBAAsB,CAAC;AAM9B;;GAEG;AACH,eAAO,MAAM,aAAa;IACxB,iCAAiC;;IAEjC,+BAA+B;;IAE/B,sCAAsC;;CAE9B,CAAC;AAMX;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,CACvB,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,EACjC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,KACd,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAMD;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,EACjC,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAQf;AAMD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAG9E;AAMD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,OAAO,GAAG,MAAM,CAI1D;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,OAAO,EAClB,GAAG,CAAC,EAAE,MAAM,GACX,MAAM,CAIR;AAMD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAQpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,GAAG,EAAE,OAAO,EAAE,EACd,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAQpB;AAMD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,GAClB,MAAM,CAER;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,EAAE,GAChB,MAAM,CAMR"}
|