smart-image-scraper-mcp 2.4.0 → 2.4.2

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 CHANGED
@@ -1,58 +1,90 @@
1
1
  # 全网智能图片抓取 MCP 服务器
2
2
 
3
- 基于 Node.js 和 Model Context Protocol (MCP) 开发的智能图片代理工具。该工具让 AI 客户端(如 Claude Desktop)能够通过自然语言指令,实现全网图片资源的搜索、验证、提取与本地化管理。
3
+ [![npm version](https://img.shields.io/npm/v/smart-image-scraper-mcp.svg)](https://www.npmjs.com/package/smart-image-scraper-mcp)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
5
 
5
- ## 功能特性
6
+ 基于 Node.js 和 Model Context Protocol (MCP) 开发的**高性能**智能图片抓取工具。让 AI 客户端(如 Claude Desktop、Windsurf)能够通过自然语言指令,实现全网图片资源的搜索、验证、下载与本地化管理。
6
7
 
7
- - **双模式运行**:
8
- - `link` 模式:仅返回验证过的图片直链
9
- - `download` 模式:下载图片到本地并生成元数据
10
- - **批量处理**:支持逗号分隔的多关键词批量搜索
11
- - **智能验证**:自动验证图片链接可访问性
12
- - **并发控制**:合理的并发限制,防止服务器过载
13
- - **元数据记录**:下载模式自动生成 metadata.json
8
+ ## ✨ 核心特性
9
+
10
+ ### 🚀 高性能架构 (v2.4.0)
11
+ - **多请求并行**:同时处理 5 个 MCP 请求
12
+ - **并行翻页搜索**:同时获取多页结果,速度提升 5x
13
+ - **HTTP 连接池**:Keep-Alive 复用 TCP 连接
14
+ - **智能缓存**:LRU 缓存减少重复请求
15
+ - **请求队列管理**:自动资源释放,防止内存泄漏
16
+
17
+ ### 📷 双模式运行
18
+ - **`link` 模式**:快速返回图片直链(默认跳过 HTTP 验证)
19
+ - **`download` 模式**:下载到本地,自动按质量排序
20
+
21
+ ### 🎯 高级功能
22
+ - **批量处理**:逗号分隔多关键词批量搜索
23
+ - **尺寸过滤**:small/medium/large/wallpaper
24
+ - **宽高比过滤**:wide(横屏)/tall(竖屏)/square(正方形)
25
+ - **尺寸统一**:下载后自动裁剪/缩放到指定尺寸
26
+ - **质量优先**:自动按图片质量排序,高清优先
14
27
 
15
28
  ## 安装
16
29
 
17
- ```bash
18
- # 进入项目目录
19
- cd 图片爬取mcp
30
+ ### 方式一:npm 全局安装(推荐)
20
31
 
21
- # 安装依赖
22
- npm install
32
+ ```bash
33
+ npm install -g smart-image-scraper-mcp
23
34
  ```
24
35
 
25
- ## 配置
36
+ ### 方式二:本地开发
26
37
 
27
- 可以通过环境变量配置:
38
+ ```bash
39
+ git clone https://github.com/your-repo/smart-image-scraper-mcp.git
40
+ cd smart-image-scraper-mcp
41
+ npm install
42
+ ```
28
43
 
29
- | 变量名 | 说明 | 默认值 |
30
- |--------|------|--------|
31
- | `SAVE_ROOT` | 图片下载根目录 | `./images` |
44
+ ## 快速开始
32
45
 
33
- ## 使用方法
46
+ ### 1. 配置 MCP 客户端
34
47
 
35
- ### 作为 MCP 服务器运行
48
+ **Windsurf 配置** (`~/.codeium/windsurf/mcp_config.json`):
36
49
 
37
- ```bash
38
- npm start
50
+ ```json
51
+ {
52
+ "mcpServers": {
53
+ "smart-image-scraper": {
54
+ "command": "npx",
55
+ "args": ["-y", "smart-image-scraper-mcp"]
56
+ }
57
+ }
58
+ }
39
59
  ```
40
60
 
41
- ### 在 Claude Desktop 中配置
42
-
43
- 在 Claude Desktop 的配置文件中添加:
61
+ **Claude Desktop 配置** (`claude_desktop_config.json`):
44
62
 
45
63
  ```json
46
64
  {
47
65
  "mcpServers": {
48
66
  "smart-image-scraper": {
49
- "command": "node",
50
- "args": ["D:/毕设/图片爬取mcp/src/index.js"]
67
+ "command": "npx",
68
+ "args": ["-y", "smart-image-scraper-mcp"],
69
+ "env": {
70
+ "SAVE_ROOT": "D:/images"
71
+ }
51
72
  }
52
73
  }
53
74
  }
54
75
  ```
55
76
 
77
+ ### 2. 重启客户端
78
+
79
+ 配置完成后重启 Windsurf 或 Claude Desktop。
80
+
81
+ ### 3. 开始使用
82
+
83
+ 直接用自然语言描述需求:
84
+ - "帮我搜索 10 张猫咪图片"
85
+ - "下载 20 张高清风景壁纸"
86
+ - "找一些人物头像图片"
87
+
56
88
  ## Tool Schema
57
89
 
58
90
  ### smart_scraper
@@ -98,30 +130,69 @@ npm start
98
130
  }
99
131
  ```
100
132
 
133
+ ## 架构设计
134
+
135
+ ```
136
+ ┌─────────────────────────────────────────────────────────────────────────┐
137
+ │ MCP Server (index.js) │
138
+ │ - 版本号从 package.json 动态读取 │
139
+ │ - 优雅关闭和资源清理 │
140
+ └─────────────────────────────────────────────────────────────────────────┘
141
+
142
+ ┌─────────────────────────────────────────────────────────────────────────┐
143
+ │ RequestQueue (requestQueue.js) │
144
+ │ - 最大并发: 5 个请求 │
145
+ │ - 请求超时: 60 秒 │
146
+ │ - 队列超时: 30 秒 │
147
+ │ - 自动资源释放 │
148
+ └─────────────────────────────────────────────────────────────────────────┘
149
+
150
+ ┌─────────────────────────────────────────────────────────────────────────┐
151
+ │ Orchestrator (orchestrator.js) │
152
+ │ - 关键词并发: 3 个/请求 │
153
+ │ - 智能缓存集成 │
154
+ │ - 快速模式/完整验证模式 │
155
+ └─────────────────────────────────────────────────────────────────────────┘
156
+
157
+ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
158
+ │ BingScraper │ │ GoogleScraper │ │ LinkValidator │
159
+ │ - 并行翻页(5页) │ │ - 并行翻页(5页) │ │ - 并发验证(30) │
160
+ │ - 最小延迟 50ms │ │ - 最小延迟 50ms │ │ - 超时 1.5s │
161
+ └──────────────────┘ └──────────────────┘ └──────────────────┘
162
+ ```
163
+
101
164
  ## 项目结构
102
165
 
103
166
  ```
104
- 图片爬取mcp/
167
+ smart-image-scraper-mcp/
105
168
  ├── src/
106
- │ ├── index.js # MCP 服务器入口
169
+ │ ├── index.js # MCP 服务器入口
107
170
  │ ├── config/
108
- │ │ └── index.js # 配置模块
171
+ │ │ └── index.js # 配置模块
109
172
  │ ├── infrastructure/
110
- │ │ ├── httpClient.js # HTTP 客户端封装
111
- │ │ ├── logger.js # 日志模块
112
- │ │ ├── retry.js # 重试机制(指数退避)
113
- │ │ └── proxy.js # 代理支持
173
+ │ │ ├── httpClient.js # HTTP 客户端(连接池)
174
+ │ │ ├── requestQueue.js # 请求队列管理
175
+ │ │ ├── cache.js # LRU 缓存
176
+ │ │ ├── metrics.js # 性能指标
177
+ │ │ ├── healthCheck.js # 健康检查
178
+ │ │ ├── gracefulShutdown.js # 优雅关闭
179
+ │ │ ├── rateLimiter.js # 速率限制
180
+ │ │ ├── logger.js # 日志模块
181
+ │ │ ├── retry.js # 重试机制
182
+ │ │ ├── errors.js # 错误分类
183
+ │ │ └── proxy.js # 代理支持
114
184
  │ ├── providers/
115
- │ │ ├── baseScraper.js # 抽象基类
116
- │ │ ├── bingScraper.js # Bing 搜索源实现
117
- │ │ ├── googleScraper.js # Google 搜索源实现
118
- │ │ └── index.js # 提供者索引
185
+ │ │ ├── baseScraper.js # 抽象基类
186
+ │ │ ├── bingScraper.js # Bing 搜索(并行翻页)
187
+ │ │ ├── googleScraper.js # Google 搜索(并行翻页)
188
+ │ │ └── index.js # 提供者索引
119
189
  │ └── services/
120
- │ ├── fileManager.js # 文件管理器
121
- │ ├── linkValidator.js # 链接验证器
122
- │ ├── orchestrator.js # 任务编排器
123
- └── index.js # 服务索引
124
- ├── images/ # 图片存储目录(自动创建)
190
+ │ ├── orchestrator.js # 任务编排器
191
+ │ ├── linkValidator.js # 链接验证器
192
+ │ ├── fileManager.js # 文件管理器
193
+ ├── imageProcessor.js # 图片处理器
194
+ │ └── index.js # 服务索引
195
+ ├── images/ # 图片存储目录
125
196
  ├── package.json
126
197
  └── README.md
127
198
  ```
@@ -137,35 +208,37 @@ npm start
137
208
 
138
209
  ## 生产级功能
139
210
 
140
- ### 健康检查与监控
141
- - 磁盘空间检查
142
- - 搜索源连通性检查
143
- - 内存使用监控
144
- - 缓存状态监控
211
+ ### 🔄 请求队列管理
212
+ - 最大并发 5 个请求
213
+ - 队列最大 20 个等待
214
+ - 请求超时 60 秒
215
+ - 队列等待超时 30 秒
216
+ - 自动资源释放
145
217
 
146
- ### 性能指标
218
+ ### 📊 性能指标
147
219
  - 请求成功率统计
148
- - 下载统计(数量、字节数)
220
+ - 缓存命中率统计
149
221
  - 响应时间统计(平均值、P95)
150
222
  - 错误分类统计
151
223
 
152
- ### 缓存机制
224
+ ### 💾 智能缓存
153
225
  - LRU 缓存实现
154
- - 搜索结果缓存(10分钟 TTL)
155
- - URL 验证结果缓存(30分钟 TTL)
226
+ - 搜索结果缓存(5分钟 TTL)
227
+ - 统一缓存键策略
156
228
  - 自动过期清理
157
229
 
158
- ### 速率限制
159
- - 令牌桶算法
160
- - 域名级别限制
161
- - Bing/Google 差异化配置
230
+ ### ⚡ 高性能优化
231
+ - HTTP 连接池(Keep-Alive)
232
+ - 并行翻页搜索(5页同时)
233
+ - 极速验证(1.5秒超时)
234
+ - 最小请求延迟(50ms)
162
235
 
163
- ### 错误处理
236
+ ### 🛡️ 错误处理
164
237
  - 统一错误码体系
165
238
  - 错误分类(网络/搜索/下载/验证)
166
239
  - 自动重试机制(指数退避)
167
240
 
168
- ### 优雅关闭
241
+ ### 🔒 优雅关闭
169
242
  - 信号处理(SIGINT/SIGTERM)
170
243
  - 活跃操作追踪
171
244
  - 资源清理
@@ -190,11 +263,34 @@ npm start
190
263
  npm test
191
264
  ```
192
265
 
266
+ ## 版本历史
267
+
268
+ | 版本 | 日期 | 主要更新 |
269
+ |------|------|----------|
270
+ | 2.4.0 | 2026-02 | 修复所有分析问题:超时策略统一、缓存键一致、版本号动态读取 |
271
+ | 2.3.0 | 2026-02 | 性能优化:HTTP 连接池、并行翻页搜索、内存泄漏修复 |
272
+ | 2.2.0 | 2026-02 | 请求队列管理系统、自动资源释放 |
273
+ | 2.1.0 | 2026-02 | 极速模式、快速验证、更高并发 |
274
+ | 2.0.0 | 2026-02 | 高性能并发模型、多请求并行 |
275
+ | 1.0.0 | 2026-01 | 初始版本 |
276
+
193
277
  ## 注意事项
194
278
 
195
279
  1. 请遵守目标网站的使用条款和 robots.txt
196
280
  2. 建议适度使用,避免频繁请求
197
281
  3. 下载的图片仅供个人学习使用
282
+ 4. 首次请求可能较慢(需要建立连接池)
283
+
284
+ ## 常见问题
285
+
286
+ ### Q: 搜索返回 0 张图片?
287
+ A: 检查网络连接,或尝试更换搜索源(bing → google)
288
+
289
+ ### Q: 下载速度慢?
290
+ A: 可以设置 `HTTP_PROXY` 环境变量使用代理
291
+
292
+ ### Q: 如何查看队列状态?
293
+ A: 日志中会显示 `[Queue]` 相关信息
198
294
 
199
295
  ## License
200
296
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "smart-image-scraper-mcp",
3
- "version": "2.4.0",
3
+ "version": "2.4.2",
4
4
  "description": "全网智能图片抓取 MCP 服务器 - 支持 Bing/Google 图片搜索、验证和下载",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
package/src/index.js CHANGED
@@ -145,7 +145,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
145
145
 
146
146
  // 注册工具调用处理器
147
147
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
148
+ const requestStartTime = Date.now();
148
149
  const { name, arguments: args } = request.params;
150
+
151
+ logger.info(`[MCP] 收到请求: ${name}, query="${args?.query?.substring(0, 30)}..."`);
149
152
 
150
153
  if (name !== 'smart_scraper') {
151
154
  return {
@@ -262,6 +265,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
262
265
 
263
266
  // 格式化输出
264
267
  const formattedResult = orchestrator.formatResult(result);
268
+
269
+ const totalTime = Date.now() - requestStartTime;
270
+ logger.info(`[MCP] 请求完成: ${totalTime}ms, requestId=${result.requestId}`);
265
271
 
266
272
  return {
267
273
  content: [
@@ -275,13 +281,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
275
281
  // 记录失败指标
276
282
  metrics.recordSearch(source, false, Date.now() - startTime);
277
283
  metrics.recordError(innerError);
284
+ logger.error(`[MCP] 内部错误: ${innerError.message}`);
278
285
  throw innerError;
279
286
  } finally {
280
287
  // 结束操作追踪
281
288
  operation.end();
282
289
  }
283
290
  } catch (error) {
284
- logger.error('Tool execution error', { error: error.message, stack: error.stack });
291
+ const totalTime = Date.now() - requestStartTime;
292
+ logger.error(`[MCP] 请求失败: ${totalTime}ms, error=${error.message}`);
285
293
  return {
286
294
  content: [
287
295
  {
@@ -123,12 +123,22 @@ export class RequestQueue {
123
123
 
124
124
  /**
125
125
  * 处理队列中的请求
126
+ * 注意:不使用 await,让请求并行执行
127
+ * 每个请求完成后会在 finally 中调用 _processQueue 继续处理
126
128
  */
127
129
  _processQueue() {
128
- while (this.queue.length > 0 && this.active.size < this.maxConcurrent) {
129
- const requestInfo = this.queue.shift();
130
- this._executeRequest(requestInfo);
131
- }
130
+ // 使用 setImmediate 避免调用栈过深
131
+ setImmediate(() => {
132
+ while (this.queue.length > 0 && this.active.size < this.maxConcurrent) {
133
+ const requestInfo = this.queue.shift();
134
+ if (requestInfo) {
135
+ // 不 await,让请求并行执行
136
+ this._executeRequest(requestInfo).catch(err => {
137
+ logger.error(`[Queue] Unexpected error: ${err.message}`);
138
+ });
139
+ }
140
+ }
141
+ });
132
142
  }
133
143
 
134
144
  /**
@@ -181,11 +191,15 @@ export class RequestQueue {
181
191
  // 从活跃列表移除
182
192
  this._removeFromActive(id);
183
193
 
184
- // 保存到已完成列表
185
- this._addToCompleted(requestInfo);
194
+ // 保存到已完成列表(使用 try-catch 防止错误)
195
+ try {
196
+ this._addToCompleted(requestInfo);
197
+ } catch (e) {
198
+ logger.warn(`[Queue] Failed to add to completed: ${e.message}`);
199
+ }
186
200
 
187
- // 继续处理队列
188
- this._processQueue();
201
+ // 继续处理队列(延迟执行,避免阻塞)
202
+ setImmediate(() => this._processQueue());
189
203
  }
190
204
  }
191
205
 
@@ -284,8 +298,8 @@ export class RequestQueue {
284
298
  // 全局请求队列实例
285
299
  export const requestQueue = new RequestQueue({
286
300
  maxConcurrent: 5,
287
- maxQueueSize: 20,
288
- requestTimeout: 60000,
301
+ maxQueueSize: 50, // 增加队列容量
302
+ requestTimeout: 120000, // 增加超时到 2 分钟
289
303
  });
290
304
 
291
305
  export default requestQueue;