@lmcc-dev/mult-fetch-mcp-server 1.0.3 → 1.2.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.
- package/README.md +11 -9
- package/README.zh.md +19 -10
- package/dist/i18n-test-report.json +8 -0
- package/dist/i18n-unused-keys-report.json +8 -0
- package/dist/src/client.js +75 -62
- package/dist/src/index.js +0 -0
- package/dist/src/lib/BrowserFetcher.js +12 -12
- package/dist/src/lib/NodeFetcher.js +165 -106
- package/dist/src/lib/fetch.js +40 -0
- package/dist/src/lib/fetchers/FetcherFactory.js +43 -0
- package/dist/src/lib/fetchers/browser/BrowserFetcher.js +381 -0
- package/dist/src/lib/fetchers/browser/BrowserInstance.js +180 -0
- package/dist/src/lib/fetchers/browser/PageOperations.js +168 -0
- package/dist/src/lib/fetchers/common/types.js +41 -0
- package/dist/src/lib/fetchers/common/utils.js +141 -0
- package/dist/src/lib/fetchers/index.js +62 -0
- package/dist/src/lib/fetchers/node/HttpClient.js +239 -0
- package/dist/src/lib/fetchers/node/NodeFetcher.js +180 -0
- package/dist/src/lib/i18n/index.js +105 -17
- package/dist/src/lib/i18n/keys/base.js +41 -0
- package/dist/src/lib/i18n/keys/browser.js +91 -0
- package/dist/src/lib/i18n/keys/client.js +68 -0
- package/dist/src/lib/i18n/keys/errors.js +49 -0
- package/dist/src/lib/i18n/keys/factory.js +46 -0
- package/dist/src/lib/i18n/keys/fetcher.js +87 -0
- package/dist/src/lib/i18n/keys/index.js +16 -0
- package/dist/src/lib/i18n/keys/node.js +69 -0
- package/dist/src/lib/i18n/keys/prompts.js +79 -0
- package/dist/src/lib/i18n/keys/resources.js +53 -0
- package/dist/src/lib/i18n/keys/server.js +67 -0
- package/dist/src/lib/i18n/keys/tools.js +39 -0
- package/dist/src/lib/i18n/keys.js +504 -0
- package/dist/src/lib/i18n/locales/en/browser.js +79 -55
- package/dist/src/lib/i18n/locales/en/client.js +57 -33
- package/dist/src/lib/i18n/locales/en/errors.js +36 -12
- package/dist/src/lib/i18n/locales/en/factory.js +38 -0
- package/dist/src/lib/i18n/locales/en/fetcher.js +67 -60
- package/dist/src/lib/i18n/locales/en/index.js +9 -7
- package/dist/src/lib/i18n/locales/en/node.js +57 -35
- package/dist/src/lib/i18n/locales/en/prompts.js +42 -65
- package/dist/src/lib/i18n/locales/en/resources.js +52 -40
- package/dist/src/lib/i18n/locales/en/server.js +49 -24
- package/dist/src/lib/i18n/locales/en/tools.js +27 -19
- package/dist/src/lib/i18n/locales/zh/browser.js +79 -56
- package/dist/src/lib/i18n/locales/zh/client.js +57 -32
- package/dist/src/lib/i18n/locales/zh/errors.js +36 -12
- package/dist/src/lib/i18n/locales/zh/factory.js +38 -0
- package/dist/src/lib/i18n/locales/zh/fetcher.js +67 -60
- package/dist/src/lib/i18n/locales/zh/index.js +9 -7
- package/dist/src/lib/i18n/locales/zh/node.js +61 -36
- package/dist/src/lib/i18n/locales/zh/prompts.js +35 -57
- package/dist/src/lib/i18n/locales/zh/resources.js +51 -39
- package/dist/src/lib/i18n/locales/zh/server.js +51 -25
- package/dist/src/lib/i18n/locales/zh/tools.js +27 -19
- package/dist/src/lib/i18n/logger.js +90 -19
- package/dist/src/lib/logger.js +135 -14
- package/dist/src/lib/server/browser.js +12 -18
- package/dist/src/lib/server/fetcher.js +13 -34
- package/dist/src/lib/server/index.js +2 -2
- package/dist/src/lib/server/prompts.js +1 -1
- package/dist/src/lib/server/resources.js +1 -1
- package/dist/src/lib/server/tools.js +404 -308
- package/dist/src/lib/utils/ErrorHandler.js +125 -0
- package/dist/src/lib/utils/errorDetection.js +41 -0
- package/dist/src/lib/utils/errors.js +279 -0
- package/dist/src/mcp-server.js +0 -0
- package/dist/src/test-i18n.js +139 -0
- package/dist/tests/BrowserFetcher.test.js +951 -0
- package/dist/tests/NodeFetcher.test.js +263 -0
- package/dist/tests/client.test.js +211 -0
- package/dist/tests/fetch.test.js +70 -0
- package/dist/tests/fetchers/Fetcher.test.js +108 -0
- package/dist/tests/fetchers/browser/BrowserFetcher.test.js +195 -0
- package/dist/tests/fetchers/browser/BrowserInstance.test.js +163 -0
- package/dist/tests/fetchers/node/NodeFetcher.test.js +211 -0
- package/dist/tests/i18n-missing-keys.js +364 -0
- package/dist/tests/i18n-remove-unused-keys.js +236 -0
- package/dist/tests/i18n-test-report.json +2004 -0
- package/dist/tests/i18n-unused-keys.js +425 -0
- package/dist/tests/i18n.test.js +178 -0
- package/dist/tests/logger.test.js +100 -0
- package/dist/tests/mcp-server.test.js +113 -0
- package/dist/tests/server/browser.test.js +201 -0
- package/dist/tests/server/fetcher.test.js +173 -0
- package/dist/tests/server/index.test.js +122 -0
- package/dist/tests/server/prompts.test.js +246 -0
- package/dist/tests/server/resources.test.js +395 -0
- package/dist/tests/server/tools.test.js +223 -0
- package/dist/tests/setup.js +36 -0
- package/dist/tests/src/lib/i18n/index.js +108 -0
- package/dist/tests/src/lib/i18n/keys/base.js +47 -0
- package/dist/tests/src/lib/i18n/keys/browser.js +93 -0
- package/dist/tests/src/lib/i18n/keys/client.js +70 -0
- package/dist/tests/src/lib/i18n/keys/errors.js +34 -0
- package/dist/tests/src/lib/i18n/keys/fetcher.js +84 -0
- package/dist/tests/src/lib/i18n/keys/index.js +31 -0
- package/dist/tests/src/lib/i18n/keys/node.js +56 -0
- package/dist/tests/src/lib/i18n/keys/prompts.js +82 -0
- package/dist/tests/src/lib/i18n/keys/resources.js +50 -0
- package/dist/tests/src/lib/i18n/keys/server.js +64 -0
- package/dist/tests/src/lib/i18n/keys/tools.js +34 -0
- package/dist/tests/src/lib/i18n/locales/en/browser.js +88 -0
- package/dist/tests/src/lib/i18n/locales/en/client.js +66 -0
- package/dist/tests/src/lib/i18n/locales/en/errors.js +28 -0
- package/dist/tests/src/lib/i18n/locales/en/fetcher.js +71 -0
- package/dist/tests/src/lib/i18n/locales/en/index.js +29 -0
- package/dist/tests/src/lib/i18n/locales/en/node.js +51 -0
- package/dist/tests/src/lib/i18n/locales/en/prompts.js +52 -0
- package/dist/tests/src/lib/i18n/locales/en/resources.js +50 -0
- package/dist/tests/src/lib/i18n/locales/en/server.js +56 -0
- package/dist/tests/src/lib/i18n/locales/en/tools.js +28 -0
- package/dist/tests/src/lib/i18n/locales/zh/browser.js +87 -0
- package/dist/tests/src/lib/i18n/locales/zh/client.js +66 -0
- package/dist/tests/src/lib/i18n/locales/zh/errors.js +28 -0
- package/dist/tests/src/lib/i18n/locales/zh/fetcher.js +71 -0
- package/dist/tests/src/lib/i18n/locales/zh/index.js +29 -0
- package/dist/tests/src/lib/i18n/locales/zh/node.js +51 -0
- package/dist/tests/src/lib/i18n/locales/zh/prompts.js +53 -0
- package/dist/tests/src/lib/i18n/locales/zh/resources.js +50 -0
- package/dist/tests/src/lib/i18n/locales/zh/server.js +57 -0
- package/dist/tests/src/lib/i18n/locales/zh/tools.js +28 -0
- package/dist/tests/src/lib/i18n/logger.js +114 -0
- package/dist/tests/src/lib/logger.js +181 -0
- package/dist/tests/test-direct-client.js +0 -0
- package/dist/tests/test-i18n.js +530 -0
- package/dist/tests/test-mcp-methods.js +1 -1
- package/dist/tests/test-mcp.js +0 -0
- package/dist/tests/test-mini4k.js +0 -0
- package/dist/tests/tests/test-i18n.js +588 -0
- package/dist/tests/types.test.js +57 -0
- package/dist/tests/utils/ErrorHandler.test.js +144 -0
- package/dist/vitest.config.js +29 -0
- package/package.json +32 -19
- package/dist/src/cli-language.js +0 -78
- package/dist/src/lib/example.js +0 -93
- package/dist/src/lib/server/logger.js +0 -23
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
|
-
[](https://github.com/modelcontextprotocol/typescript-sdk)
|
|
8
8
|
[](https://github.com/lmcc-dev/mult-fetch-mcp-server/stargazers)
|
|
9
9
|
[](https://github.com/lmcc-dev/mult-fetch-mcp-server/network/members)
|
|
10
10
|
[](https://github.com/lmcc-dev/mult-fetch-mcp-server/issues)
|
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
[](https://github.com/lmcc-dev/mult-fetch-mcp-server/commits/main)
|
|
14
14
|
[](https://github.com/lmcc-dev/mult-fetch-mcp-server/graphs/contributors)
|
|
15
15
|
[](https://smithery.ai/server/@lmcc-dev/mult-fetch-mcp-server)
|
|
16
|
+
[](https://codecov.io/gh/lmcc-dev/mult-fetch-mcp-server)
|
|
17
|
+
[](https://www.codefactor.io/repository/github/lmcc-dev/mult-fetch-mcp-server)
|
|
18
|
+
|
|
16
19
|
|
|
17
20
|
|
|
18
21
|
<!-- Future badges to consider:
|
|
19
|
-
[](https://codecov.io/gh/lmcc-dev/mult-fetch-mcp-server)
|
|
20
22
|
[](https://www.codefactor.io/repository/github/lmcc-dev/mult-fetch-mcp-server)
|
|
21
23
|
[](https://codeclimate.com/github/lmcc-dev/mult-fetch-mcp-server/maintainability)
|
|
22
24
|
-->
|
|
@@ -89,16 +91,16 @@ npx -y @smithery/cli install @lmcc-dev/mult-fetch-mcp-server --client claude
|
|
|
89
91
|
### Local Installation
|
|
90
92
|
|
|
91
93
|
```bash
|
|
92
|
-
|
|
94
|
+
pnpm install
|
|
93
95
|
```
|
|
94
96
|
|
|
95
97
|
### Global Installation
|
|
96
98
|
|
|
97
99
|
```bash
|
|
98
|
-
|
|
100
|
+
pnpm add -g @lmcc-dev/mult-fetch-mcp-server
|
|
99
101
|
```
|
|
100
102
|
|
|
101
|
-
Or
|
|
103
|
+
Or run directly with npx (no installation required):
|
|
102
104
|
|
|
103
105
|
```bash
|
|
104
106
|
npx @lmcc-dev/mult-fetch-mcp-server
|
|
@@ -173,13 +175,13 @@ After configuration, restart Claude desktop, and you can use the following tools
|
|
|
173
175
|
## Build
|
|
174
176
|
|
|
175
177
|
```bash
|
|
176
|
-
|
|
178
|
+
pnpm run build
|
|
177
179
|
```
|
|
178
180
|
|
|
179
181
|
## Run Server
|
|
180
182
|
|
|
181
183
|
```bash
|
|
182
|
-
|
|
184
|
+
pnpm run server
|
|
183
185
|
# or
|
|
184
186
|
node dist/index.js
|
|
185
187
|
# if globally installed, you can run directly
|
|
@@ -191,9 +193,9 @@ npx @lmcc-dev/mult-fetch-mcp-server
|
|
|
191
193
|
## Run Client
|
|
192
194
|
|
|
193
195
|
```bash
|
|
194
|
-
|
|
196
|
+
pnpm run client <method> <params_json>
|
|
195
197
|
# example
|
|
196
|
-
|
|
198
|
+
pnpm run client fetch_html '{"url": "https://example.com", "debug": true}'
|
|
197
199
|
```
|
|
198
200
|
|
|
199
201
|
## Run Tests
|
package/README.zh.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
[](https://nodejs.org/)
|
|
6
6
|
[](https://www.typescriptlang.org/)
|
|
7
|
-
[](https://github.com/modelcontextprotocol/typescript-sdk)
|
|
8
8
|
[](https://github.com/lmcc-dev/mult-fetch-mcp-server/stargazers)
|
|
9
9
|
[](https://github.com/lmcc-dev/mult-fetch-mcp-server/network/members)
|
|
10
10
|
[](https://github.com/lmcc-dev/mult-fetch-mcp-server/issues)
|
|
@@ -12,10 +12,11 @@
|
|
|
12
12
|
[](https://www.npmjs.com/package/@lmcc-dev/mult-fetch-mcp-server)
|
|
13
13
|
[](https://github.com/lmcc-dev/mult-fetch-mcp-server/commits/main)
|
|
14
14
|
[](https://github.com/lmcc-dev/mult-fetch-mcp-server/graphs/contributors)
|
|
15
|
-
|
|
16
|
-
<!-- 未来可考虑添加的徽章:
|
|
17
15
|
[](https://codecov.io/gh/lmcc-dev/mult-fetch-mcp-server)
|
|
18
16
|
[](https://www.codefactor.io/repository/github/lmcc-dev/mult-fetch-mcp-server)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
<!-- 未来可考虑添加的徽章:
|
|
19
20
|
[](https://codeclimate.com/github/lmcc-dev/mult-fetch-mcp-server/maintainability)
|
|
20
21
|
-->
|
|
21
22
|
|
|
@@ -76,22 +77,30 @@ fetch-mcp/
|
|
|
76
77
|
|
|
77
78
|
## 安装
|
|
78
79
|
|
|
80
|
+
### 通过 Smithery 安装
|
|
81
|
+
|
|
82
|
+
要通过 [Smithery](https://smithery.ai/server/@lmcc-dev/mult-fetch-mcp-server) 自动为 Claude 桌面版安装 Mult Fetch MCP Server:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npx -y @smithery/cli install @lmcc-dev/mult-fetch-mcp-server --client claude
|
|
86
|
+
```
|
|
87
|
+
|
|
79
88
|
### 本地安装
|
|
80
89
|
|
|
81
90
|
```bash
|
|
82
|
-
|
|
91
|
+
pnpm install
|
|
83
92
|
```
|
|
84
93
|
|
|
85
94
|
### 全局安装
|
|
86
95
|
|
|
87
96
|
```bash
|
|
88
|
-
|
|
97
|
+
pnpm add -g @lmcc-dev/mult-fetch-mcp-server
|
|
89
98
|
```
|
|
90
99
|
|
|
91
100
|
或者直接使用 npx 运行(无需安装):
|
|
92
101
|
|
|
93
102
|
```bash
|
|
94
|
-
npx mult-fetch-mcp-server
|
|
103
|
+
npx @lmcc-dev/mult-fetch-mcp-server
|
|
95
104
|
```
|
|
96
105
|
|
|
97
106
|
## 与 Claude 集成
|
|
@@ -163,13 +172,13 @@ npx mult-fetch-mcp-server
|
|
|
163
172
|
## 构建
|
|
164
173
|
|
|
165
174
|
```bash
|
|
166
|
-
|
|
175
|
+
pnpm run build
|
|
167
176
|
```
|
|
168
177
|
|
|
169
178
|
## 运行服务器
|
|
170
179
|
|
|
171
180
|
```bash
|
|
172
|
-
|
|
181
|
+
pnpm run server
|
|
173
182
|
# 或者
|
|
174
183
|
node dist/index.js
|
|
175
184
|
# 如果全局安装,可以直接运行
|
|
@@ -181,9 +190,9 @@ npx mult-fetch-mcp-server
|
|
|
181
190
|
## 运行客户端
|
|
182
191
|
|
|
183
192
|
```bash
|
|
184
|
-
|
|
193
|
+
pnpm run client <method> <params_json>
|
|
185
194
|
# 例如
|
|
186
|
-
|
|
195
|
+
pnpm run client fetch_html '{"url": "https://example.com", "debug": true}'
|
|
187
196
|
```
|
|
188
197
|
|
|
189
198
|
## 运行测试
|
package/dist/src/client.js
CHANGED
|
@@ -9,6 +9,7 @@ import path from 'path';
|
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
10
|
import { log, COMPONENTS } from './lib/logger.js';
|
|
11
11
|
import { execSync } from 'child_process';
|
|
12
|
+
import { isAccessDeniedError, isNetworkError } from './lib/utils/errorDetection.js';
|
|
12
13
|
// 获取当前文件的目录路径 (Get the directory path of the current file)
|
|
13
14
|
const __filename = fileURLToPath(import.meta.url);
|
|
14
15
|
const __dirname = path.dirname(__filename);
|
|
@@ -25,43 +26,40 @@ const __dirname = path.dirname(__filename);
|
|
|
25
26
|
*/
|
|
26
27
|
function responseRequiresBrowser(response, debug = false) {
|
|
27
28
|
if (response.isError) {
|
|
28
|
-
const errorText = response.content[0].text
|
|
29
|
+
const errorText = response.content[0].text;
|
|
29
30
|
if (debug) {
|
|
30
|
-
log('
|
|
31
|
+
log('client.fetchError', debug, { url: '', error: errorText }, COMPONENTS.CLIENT);
|
|
31
32
|
// 尝试从错误信息中提取HTTP状态码 (Try to extract HTTP status code from error message)
|
|
32
|
-
const statusCodeMatch =
|
|
33
|
+
const statusCodeMatch = errorText.match(/(\b[45]\d\d\b)/);
|
|
33
34
|
if (statusCodeMatch) {
|
|
34
35
|
log('client.statusCodeDetected', debug, { code: statusCodeMatch[0] }, COMPONENTS.CLIENT);
|
|
35
36
|
}
|
|
36
37
|
// 尝试解析更详细的错误原因
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
log('errors.timeout', debug, { timeout: '' }, COMPONENTS.CLIENT);
|
|
38
|
+
if (isAccessDeniedError(errorText)) {
|
|
39
|
+
if (errorText.toLowerCase().includes('403') || errorText.toLowerCase().includes('forbidden')) {
|
|
40
|
+
log('errors.forbidden', debug, {}, COMPONENTS.CLIENT);
|
|
41
|
+
}
|
|
42
|
+
else if (errorText.toLowerCase().includes('cloudflare')) {
|
|
43
|
+
log('errors.cloudflareProtection', debug, {}, COMPONENTS.CLIENT);
|
|
44
|
+
}
|
|
45
|
+
else if (errorText.toLowerCase().includes('captcha')) {
|
|
46
|
+
log('errors.captchaRequired', debug, {}, COMPONENTS.CLIENT);
|
|
47
|
+
}
|
|
48
48
|
}
|
|
49
|
-
else if (
|
|
50
|
-
|
|
49
|
+
else if (isNetworkError(errorText)) {
|
|
50
|
+
if (errorText.toLowerCase().includes('timeout')) {
|
|
51
|
+
log('errors.timeout', debug, { timeout: '' }, COMPONENTS.CLIENT);
|
|
52
|
+
}
|
|
53
|
+
else if (errorText.toLowerCase().includes('socket') || errorText.toLowerCase().includes('econnrefused')) {
|
|
54
|
+
log('errors.connectionProblem', debug, {}, COMPONENTS.CLIENT);
|
|
55
|
+
}
|
|
51
56
|
}
|
|
52
57
|
}
|
|
53
|
-
return errorText
|
|
54
|
-
errorText
|
|
55
|
-
errorText.includes('
|
|
56
|
-
errorText.includes('
|
|
57
|
-
errorText.includes('
|
|
58
|
-
errorText.includes('javascript required') ||
|
|
59
|
-
errorText.includes('timeout') ||
|
|
60
|
-
errorText.includes('connect timeout') ||
|
|
61
|
-
errorText.includes('socket') ||
|
|
62
|
-
errorText.includes('econnrefused') ||
|
|
63
|
-
errorText.includes('und_err_connect_timeout') ||
|
|
64
|
-
errorText.includes('fetch failed');
|
|
58
|
+
return isAccessDeniedError(errorText) ||
|
|
59
|
+
isNetworkError(errorText) ||
|
|
60
|
+
errorText.toLowerCase().includes('javascript required') ||
|
|
61
|
+
errorText.toLowerCase().includes('und_err_connect_timeout') ||
|
|
62
|
+
errorText.toLowerCase().includes('fetch failed');
|
|
65
63
|
}
|
|
66
64
|
return false;
|
|
67
65
|
}
|
|
@@ -106,67 +104,60 @@ async function smartFetch(params) {
|
|
|
106
104
|
// 在调试模式下打印响应结果的摘要 (Print response result summary in debug mode)
|
|
107
105
|
if (debug) {
|
|
108
106
|
if (result.isError) {
|
|
109
|
-
log('client.fetchFailed', debug, { error: result.content[0].text
|
|
107
|
+
log('client.fetchFailed', debug, { url, error: result.content[0].text }, COMPONENTS.CLIENT);
|
|
110
108
|
}
|
|
111
109
|
else {
|
|
112
|
-
|
|
113
|
-
log('client.fetchSuccess', debug, { length: contentLength }, COMPONENTS.CLIENT);
|
|
110
|
+
log('client.fetchSuccess', debug, { url }, COMPONENTS.CLIENT);
|
|
114
111
|
}
|
|
115
112
|
}
|
|
116
|
-
//
|
|
117
|
-
if (
|
|
113
|
+
// 检查是否需要切换到浏览器模式 (Check if need to switch to browser mode)
|
|
114
|
+
if (result.isError && responseRequiresBrowser(result, debug) && !params.useBrowser) {
|
|
118
115
|
log('client.browserModeNeeded', debug, { url }, COMPONENTS.CLIENT);
|
|
119
|
-
// 切换到浏览器模式重试 (Switch to browser mode and retry)
|
|
120
|
-
params.useBrowser = true;
|
|
121
|
-
// 设置关闭浏览器选项,确保资源被释放 (Set close browser option to ensure resources are released)
|
|
122
|
-
params.closeBrowser = true;
|
|
123
116
|
log('client.retryingWithBrowser', debug, { url }, COMPONENTS.CLIENT);
|
|
117
|
+
// 切换到浏览器模式重试 (Switch to browser mode and retry)
|
|
124
118
|
const browserResult = await client.callTool({
|
|
125
119
|
name: method,
|
|
126
|
-
arguments:
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if (debug) {
|
|
130
|
-
if (browserResult.isError) {
|
|
131
|
-
log('client.browserModeFetchFailed', debug, { error: browserResult.content[0].text.substring(0, 150) + (browserResult.content[0].text.length > 150 ? '...' : '') }, COMPONENTS.CLIENT);
|
|
132
|
-
}
|
|
133
|
-
else {
|
|
134
|
-
const contentLength = browserResult.content[0].text.length;
|
|
135
|
-
log('client.browserModeFetchSuccess', debug, { length: contentLength }, COMPONENTS.CLIENT);
|
|
120
|
+
arguments: {
|
|
121
|
+
...params,
|
|
122
|
+
useBrowser: true
|
|
136
123
|
}
|
|
124
|
+
});
|
|
125
|
+
if (browserResult.isError) {
|
|
126
|
+
log('client.browserModeFetchFailed', debug, { url, error: browserResult.content[0].text }, COMPONENTS.CLIENT);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
log('client.browserModeFetchSuccess', debug, { url }, COMPONENTS.CLIENT);
|
|
137
130
|
}
|
|
138
131
|
return browserResult;
|
|
139
132
|
}
|
|
133
|
+
if (result.isError) {
|
|
134
|
+
log('client.fetchFailed', debug, { url, error: result.content[0].text }, COMPONENTS.CLIENT);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
log('client.fetchSuccess', debug, { url }, COMPONENTS.CLIENT);
|
|
138
|
+
}
|
|
140
139
|
return result;
|
|
141
140
|
}
|
|
142
141
|
else {
|
|
143
|
-
//
|
|
142
|
+
// 直接使用指定的模式 (Directly use the specified mode)
|
|
144
143
|
log('client.usingMode', debug, { mode: params.useBrowser ? 'browser' : 'standard', url }, COMPONENTS.CLIENT);
|
|
145
|
-
// 如果使用浏览器模式,设置关闭浏览器选项
|
|
146
|
-
if (params.useBrowser) {
|
|
147
|
-
params.closeBrowser = true;
|
|
148
|
-
}
|
|
149
144
|
const result = await client.callTool({
|
|
150
145
|
name: method,
|
|
151
146
|
arguments: params
|
|
152
147
|
});
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
const contentLength = result.content[0].text.length;
|
|
160
|
-
log('client.fetchSuccess', debug, { length: contentLength }, COMPONENTS.CLIENT);
|
|
161
|
-
}
|
|
148
|
+
if (result.isError) {
|
|
149
|
+
log('client.fetchFailed', debug, { url, error: result.content[0].text }, COMPONENTS.CLIENT);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
log('client.fetchSuccess', debug, { url }, COMPONENTS.CLIENT);
|
|
162
153
|
}
|
|
163
154
|
return result;
|
|
164
155
|
}
|
|
165
156
|
}
|
|
166
157
|
finally {
|
|
167
158
|
// 关闭客户端连接 (Close client connection)
|
|
168
|
-
await client.close();
|
|
169
159
|
log('client.serverClosed', debug, {}, COMPONENTS.CLIENT);
|
|
160
|
+
await client.close();
|
|
170
161
|
}
|
|
171
162
|
}
|
|
172
163
|
/**
|
|
@@ -188,6 +179,17 @@ async function main() {
|
|
|
188
179
|
}
|
|
189
180
|
catch (error) {
|
|
190
181
|
log('client.invalidJson', true, {}, COMPONENTS.CLIENT);
|
|
182
|
+
// 返回标准错误结构体 (Return standard error structure)
|
|
183
|
+
const errorResult = {
|
|
184
|
+
isError: true,
|
|
185
|
+
content: [
|
|
186
|
+
{
|
|
187
|
+
type: "text",
|
|
188
|
+
text: `Invalid JSON parameter: ${paramsJson}`
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
};
|
|
192
|
+
process.stdout.write(JSON.stringify(errorResult, null, 2));
|
|
191
193
|
process.exit(1);
|
|
192
194
|
}
|
|
193
195
|
const debug = params.debug === true;
|
|
@@ -272,6 +274,17 @@ async function main() {
|
|
|
272
274
|
}
|
|
273
275
|
catch (error) {
|
|
274
276
|
log('client.requestFailed', debug, { error: error.message }, COMPONENTS.CLIENT);
|
|
277
|
+
// 即使在出错的情况下也输出标准结构体 (Output standard structure even in case of error)
|
|
278
|
+
const errorResult = {
|
|
279
|
+
isError: true,
|
|
280
|
+
content: [
|
|
281
|
+
{
|
|
282
|
+
type: "text",
|
|
283
|
+
text: `Client error: ${error.message}`
|
|
284
|
+
}
|
|
285
|
+
]
|
|
286
|
+
};
|
|
287
|
+
process.stdout.write(JSON.stringify(errorResult, null, 2));
|
|
275
288
|
process.exit(1);
|
|
276
289
|
}
|
|
277
290
|
}
|
package/dist/src/index.js
CHANGED
|
File without changes
|
|
@@ -88,7 +88,7 @@ export class BrowserFetcher {
|
|
|
88
88
|
const heapTotal = Math.round(memoryUsage.heapTotal / 1024 / 1024);
|
|
89
89
|
const rss = Math.round(memoryUsage.rss / 1024 / 1024);
|
|
90
90
|
// 记录内存使用情况
|
|
91
|
-
log('browser.memoryUsage', debug, { heapUsed
|
|
91
|
+
log('browser.memoryUsage', debug, { usage: heapUsed }, COMPONENTS.BROWSER_FETCH);
|
|
92
92
|
// 如果内存使用过高,记录警告
|
|
93
93
|
if (heapUsed > 500 || rss > 1000) {
|
|
94
94
|
log('browser.memoryTooHigh', debug, { heapUsed, heapTotal, rss }, COMPONENTS.BROWSER_FETCH);
|
|
@@ -473,7 +473,7 @@ export class BrowserFetcher {
|
|
|
473
473
|
const domain = this.getDomain(url);
|
|
474
474
|
const storedCookies = this.getCookies(domain);
|
|
475
475
|
if (storedCookies && saveCookies) {
|
|
476
|
-
log('browser.usingStoredCookies', debug, { domain
|
|
476
|
+
log('browser.usingStoredCookies', debug, { domain }, COMPONENTS.BROWSER_FETCH);
|
|
477
477
|
await page.setExtraHTTPHeaders({
|
|
478
478
|
'Cookie': storedCookies
|
|
479
479
|
});
|
|
@@ -483,7 +483,7 @@ export class BrowserFetcher {
|
|
|
483
483
|
log('browser.usingProxy', debug, { proxy: effectiveProxy }, COMPONENTS.BROWSER_FETCH);
|
|
484
484
|
}
|
|
485
485
|
// 导航到URL
|
|
486
|
-
log('browser.navigating', debug, {
|
|
486
|
+
log('browser.navigating', debug, { url }, COMPONENTS.BROWSER_FETCH);
|
|
487
487
|
await page.goto(url, {
|
|
488
488
|
waitUntil: 'networkidle2',
|
|
489
489
|
timeout: timeout
|
|
@@ -491,27 +491,27 @@ export class BrowserFetcher {
|
|
|
491
491
|
// 尝试处理Cloudflare保护
|
|
492
492
|
const bypassedCloudflare = await this.handleCloudflareProtection(page, url, debug);
|
|
493
493
|
if (!bypassedCloudflare) {
|
|
494
|
-
log('browser.continuingWithoutBypass', debug, {
|
|
494
|
+
log('browser.continuingWithoutBypass', debug, {}, COMPONENTS.BROWSER_FETCH);
|
|
495
495
|
}
|
|
496
496
|
// 等待选择器
|
|
497
|
-
log('browser.waitingForSelector', debug, { selector: waitForSelector
|
|
497
|
+
log('browser.waitingForSelector', debug, { selector: waitForSelector }, COMPONENTS.BROWSER_FETCH);
|
|
498
498
|
await page.waitForSelector(waitForSelector, {
|
|
499
499
|
timeout: timeout
|
|
500
500
|
}).catch(() => { });
|
|
501
501
|
// 等待额外时间
|
|
502
|
-
log('browser.waitingForTimeout', debug, { timeout: waitForTimeout
|
|
502
|
+
log('browser.waitingForTimeout', debug, { timeout: waitForTimeout }, COMPONENTS.BROWSER_FETCH);
|
|
503
503
|
await new Promise(resolve => setTimeout(resolve, waitForTimeout));
|
|
504
504
|
// 如果需要滚动到底部
|
|
505
505
|
if (scrollToBottom) {
|
|
506
|
-
log('browser.scrolling', debug, {
|
|
506
|
+
log('browser.scrolling', debug, {}, COMPONENTS.BROWSER_FETCH);
|
|
507
507
|
await this.autoScroll(page, debug);
|
|
508
508
|
}
|
|
509
509
|
// 获取页面内容
|
|
510
|
-
log('browser.gettingContent', debug, {
|
|
510
|
+
log('browser.gettingContent', debug, {}, COMPONENTS.BROWSER_FETCH);
|
|
511
511
|
const content = await page.content();
|
|
512
512
|
// 如果需要保存cookies
|
|
513
513
|
if (saveCookies) {
|
|
514
|
-
log('browser.savingCookies', debug, {
|
|
514
|
+
log('browser.savingCookies', debug, { domain }, COMPONENTS.BROWSER_FETCH);
|
|
515
515
|
const cookies = await page.evaluate(() => document.cookie);
|
|
516
516
|
if (cookies) {
|
|
517
517
|
this.saveCookies(url, cookies);
|
|
@@ -519,16 +519,16 @@ export class BrowserFetcher {
|
|
|
519
519
|
}
|
|
520
520
|
// 记录内容长度
|
|
521
521
|
const contentLength = content.length;
|
|
522
|
-
log('browser.contentLength', debug, { length: contentLength
|
|
522
|
+
log('browser.contentLength', debug, { length: contentLength }, COMPONENTS.BROWSER_FETCH);
|
|
523
523
|
// 如果内容太长,截断它
|
|
524
524
|
let finalContent = content;
|
|
525
525
|
if (contentLength > 10 * 1024 * 1024) { // 10MB
|
|
526
526
|
finalContent = content.substring(0, 10 * 1024 * 1024);
|
|
527
|
-
log('browser.contentTruncated', debug, {
|
|
527
|
+
log('browser.contentTruncated', debug, {}, COMPONENTS.BROWSER_FETCH);
|
|
528
528
|
}
|
|
529
529
|
// 关闭页面
|
|
530
530
|
await page.close();
|
|
531
|
-
log('browser.pageClosed', debug, {
|
|
531
|
+
log('browser.pageClosed', debug, {}, COMPONENTS.BROWSER_FETCH);
|
|
532
532
|
// 如果需要关闭浏览器
|
|
533
533
|
if (closeBrowser) {
|
|
534
534
|
await this.closeBrowser(debug);
|