smart-image-scraper-mcp 2.9.3 → 2.10.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/package.json +1 -1
- package/src/index.js +16 -2
- package/src/services/orchestrator.js +25 -7
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -175,7 +175,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
175
175
|
};
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
// MCP 层最外层超时保护(60秒硬限制)
|
|
179
|
+
const MCP_TIMEOUT = 60000;
|
|
180
|
+
|
|
181
|
+
const executeWithTimeout = async () => {
|
|
179
182
|
// 主流做法:每个请求创建新的 Orchestrator 实例,确保无状态
|
|
180
183
|
const orchestrator = new Orchestrator();
|
|
181
184
|
|
|
@@ -211,13 +214,24 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
211
214
|
return {
|
|
212
215
|
content: [{ type: 'text', text: formattedResult }],
|
|
213
216
|
};
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
// 使用 Promise.race 确保一定会在超时内返回
|
|
221
|
+
const result = await Promise.race([
|
|
222
|
+
executeWithTimeout(),
|
|
223
|
+
new Promise((_, reject) =>
|
|
224
|
+
setTimeout(() => reject(new Error('MCP_TIMEOUT: 请求超时(60秒),请减少关键词数量或稍后重试')), MCP_TIMEOUT)
|
|
225
|
+
)
|
|
226
|
+
]);
|
|
227
|
+
return result;
|
|
214
228
|
} catch (error) {
|
|
215
229
|
// 主流做法:简洁的错误处理,使用 stderr 输出日志
|
|
216
230
|
console.error(`[MCP Error] ${error.message}`);
|
|
217
231
|
return {
|
|
218
232
|
content: [{
|
|
219
233
|
type: 'text',
|
|
220
|
-
text: `## ❌ 执行错误\n\n**错误信息**: ${error.message}\n\n
|
|
234
|
+
text: `## ❌ 执行错误\n\n**错误信息**: ${error.message}\n\n请减少关键词数量或稍后重试。`
|
|
221
235
|
}],
|
|
222
236
|
isError: true,
|
|
223
237
|
};
|
|
@@ -403,7 +403,7 @@ export class Orchestrator {
|
|
|
403
403
|
const options = { size, safeSearch, aspect, targetSize, fit, position };
|
|
404
404
|
|
|
405
405
|
const startTime = Date.now();
|
|
406
|
-
|
|
406
|
+
let keywords = this.parseKeywords(query);
|
|
407
407
|
|
|
408
408
|
if (keywords.length === 0) {
|
|
409
409
|
return {
|
|
@@ -412,6 +412,13 @@ export class Orchestrator {
|
|
|
412
412
|
};
|
|
413
413
|
}
|
|
414
414
|
|
|
415
|
+
// 限制最大关键词数量为 10 个,避免阻塞
|
|
416
|
+
const MAX_KEYWORDS = 10;
|
|
417
|
+
if (keywords.length > MAX_KEYWORDS) {
|
|
418
|
+
logger.warn(`Too many keywords (${keywords.length}), limiting to ${MAX_KEYWORDS}`);
|
|
419
|
+
keywords = keywords.slice(0, MAX_KEYWORDS);
|
|
420
|
+
}
|
|
421
|
+
|
|
415
422
|
logger.info(`Starting task: mode=${mode}, keywords=${keywords.join(', ')}, count=${count}, source=${source}`);
|
|
416
423
|
|
|
417
424
|
// 根据模式选择处理函数
|
|
@@ -419,12 +426,23 @@ export class Orchestrator {
|
|
|
419
426
|
? this.processKeywordLink.bind(this)
|
|
420
427
|
: this.processKeywordDownload.bind(this);
|
|
421
428
|
|
|
422
|
-
//
|
|
423
|
-
const results =
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
429
|
+
// 串行处理关键词,避免阻塞事件循环
|
|
430
|
+
const results = [];
|
|
431
|
+
for (const keyword of keywords) {
|
|
432
|
+
try {
|
|
433
|
+
const result = await processFunc(keyword, count, source, options);
|
|
434
|
+
results.push(result);
|
|
435
|
+
// 让出事件循环,确保 MCP 通信不被阻塞
|
|
436
|
+
await new Promise(resolve => setImmediate(resolve));
|
|
437
|
+
} catch (error) {
|
|
438
|
+
results.push({
|
|
439
|
+
keyword,
|
|
440
|
+
success: false,
|
|
441
|
+
error: error.message,
|
|
442
|
+
duration: 0,
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
}
|
|
428
446
|
|
|
429
447
|
// 汇总结果
|
|
430
448
|
const successResults = results.filter(r => r.success);
|