@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.
Files changed (136) hide show
  1. package/README.md +11 -9
  2. package/README.zh.md +19 -10
  3. package/dist/i18n-test-report.json +8 -0
  4. package/dist/i18n-unused-keys-report.json +8 -0
  5. package/dist/src/client.js +75 -62
  6. package/dist/src/index.js +0 -0
  7. package/dist/src/lib/BrowserFetcher.js +12 -12
  8. package/dist/src/lib/NodeFetcher.js +165 -106
  9. package/dist/src/lib/fetch.js +40 -0
  10. package/dist/src/lib/fetchers/FetcherFactory.js +43 -0
  11. package/dist/src/lib/fetchers/browser/BrowserFetcher.js +381 -0
  12. package/dist/src/lib/fetchers/browser/BrowserInstance.js +180 -0
  13. package/dist/src/lib/fetchers/browser/PageOperations.js +168 -0
  14. package/dist/src/lib/fetchers/common/types.js +41 -0
  15. package/dist/src/lib/fetchers/common/utils.js +141 -0
  16. package/dist/src/lib/fetchers/index.js +62 -0
  17. package/dist/src/lib/fetchers/node/HttpClient.js +239 -0
  18. package/dist/src/lib/fetchers/node/NodeFetcher.js +180 -0
  19. package/dist/src/lib/i18n/index.js +105 -17
  20. package/dist/src/lib/i18n/keys/base.js +41 -0
  21. package/dist/src/lib/i18n/keys/browser.js +91 -0
  22. package/dist/src/lib/i18n/keys/client.js +68 -0
  23. package/dist/src/lib/i18n/keys/errors.js +49 -0
  24. package/dist/src/lib/i18n/keys/factory.js +46 -0
  25. package/dist/src/lib/i18n/keys/fetcher.js +87 -0
  26. package/dist/src/lib/i18n/keys/index.js +16 -0
  27. package/dist/src/lib/i18n/keys/node.js +69 -0
  28. package/dist/src/lib/i18n/keys/prompts.js +79 -0
  29. package/dist/src/lib/i18n/keys/resources.js +53 -0
  30. package/dist/src/lib/i18n/keys/server.js +67 -0
  31. package/dist/src/lib/i18n/keys/tools.js +39 -0
  32. package/dist/src/lib/i18n/keys.js +504 -0
  33. package/dist/src/lib/i18n/locales/en/browser.js +79 -55
  34. package/dist/src/lib/i18n/locales/en/client.js +57 -33
  35. package/dist/src/lib/i18n/locales/en/errors.js +36 -12
  36. package/dist/src/lib/i18n/locales/en/factory.js +38 -0
  37. package/dist/src/lib/i18n/locales/en/fetcher.js +67 -60
  38. package/dist/src/lib/i18n/locales/en/index.js +9 -7
  39. package/dist/src/lib/i18n/locales/en/node.js +57 -35
  40. package/dist/src/lib/i18n/locales/en/prompts.js +42 -65
  41. package/dist/src/lib/i18n/locales/en/resources.js +52 -40
  42. package/dist/src/lib/i18n/locales/en/server.js +49 -24
  43. package/dist/src/lib/i18n/locales/en/tools.js +27 -19
  44. package/dist/src/lib/i18n/locales/zh/browser.js +79 -56
  45. package/dist/src/lib/i18n/locales/zh/client.js +57 -32
  46. package/dist/src/lib/i18n/locales/zh/errors.js +36 -12
  47. package/dist/src/lib/i18n/locales/zh/factory.js +38 -0
  48. package/dist/src/lib/i18n/locales/zh/fetcher.js +67 -60
  49. package/dist/src/lib/i18n/locales/zh/index.js +9 -7
  50. package/dist/src/lib/i18n/locales/zh/node.js +61 -36
  51. package/dist/src/lib/i18n/locales/zh/prompts.js +35 -57
  52. package/dist/src/lib/i18n/locales/zh/resources.js +51 -39
  53. package/dist/src/lib/i18n/locales/zh/server.js +51 -25
  54. package/dist/src/lib/i18n/locales/zh/tools.js +27 -19
  55. package/dist/src/lib/i18n/logger.js +90 -19
  56. package/dist/src/lib/logger.js +135 -14
  57. package/dist/src/lib/server/browser.js +12 -18
  58. package/dist/src/lib/server/fetcher.js +13 -34
  59. package/dist/src/lib/server/index.js +2 -2
  60. package/dist/src/lib/server/prompts.js +1 -1
  61. package/dist/src/lib/server/resources.js +1 -1
  62. package/dist/src/lib/server/tools.js +404 -308
  63. package/dist/src/lib/utils/ErrorHandler.js +125 -0
  64. package/dist/src/lib/utils/errorDetection.js +41 -0
  65. package/dist/src/lib/utils/errors.js +279 -0
  66. package/dist/src/mcp-server.js +0 -0
  67. package/dist/src/test-i18n.js +139 -0
  68. package/dist/tests/BrowserFetcher.test.js +951 -0
  69. package/dist/tests/NodeFetcher.test.js +263 -0
  70. package/dist/tests/client.test.js +211 -0
  71. package/dist/tests/fetch.test.js +70 -0
  72. package/dist/tests/fetchers/Fetcher.test.js +108 -0
  73. package/dist/tests/fetchers/browser/BrowserFetcher.test.js +195 -0
  74. package/dist/tests/fetchers/browser/BrowserInstance.test.js +163 -0
  75. package/dist/tests/fetchers/node/NodeFetcher.test.js +211 -0
  76. package/dist/tests/i18n-missing-keys.js +364 -0
  77. package/dist/tests/i18n-remove-unused-keys.js +236 -0
  78. package/dist/tests/i18n-test-report.json +2004 -0
  79. package/dist/tests/i18n-unused-keys.js +425 -0
  80. package/dist/tests/i18n.test.js +178 -0
  81. package/dist/tests/logger.test.js +100 -0
  82. package/dist/tests/mcp-server.test.js +113 -0
  83. package/dist/tests/server/browser.test.js +201 -0
  84. package/dist/tests/server/fetcher.test.js +173 -0
  85. package/dist/tests/server/index.test.js +122 -0
  86. package/dist/tests/server/prompts.test.js +246 -0
  87. package/dist/tests/server/resources.test.js +395 -0
  88. package/dist/tests/server/tools.test.js +223 -0
  89. package/dist/tests/setup.js +36 -0
  90. package/dist/tests/src/lib/i18n/index.js +108 -0
  91. package/dist/tests/src/lib/i18n/keys/base.js +47 -0
  92. package/dist/tests/src/lib/i18n/keys/browser.js +93 -0
  93. package/dist/tests/src/lib/i18n/keys/client.js +70 -0
  94. package/dist/tests/src/lib/i18n/keys/errors.js +34 -0
  95. package/dist/tests/src/lib/i18n/keys/fetcher.js +84 -0
  96. package/dist/tests/src/lib/i18n/keys/index.js +31 -0
  97. package/dist/tests/src/lib/i18n/keys/node.js +56 -0
  98. package/dist/tests/src/lib/i18n/keys/prompts.js +82 -0
  99. package/dist/tests/src/lib/i18n/keys/resources.js +50 -0
  100. package/dist/tests/src/lib/i18n/keys/server.js +64 -0
  101. package/dist/tests/src/lib/i18n/keys/tools.js +34 -0
  102. package/dist/tests/src/lib/i18n/locales/en/browser.js +88 -0
  103. package/dist/tests/src/lib/i18n/locales/en/client.js +66 -0
  104. package/dist/tests/src/lib/i18n/locales/en/errors.js +28 -0
  105. package/dist/tests/src/lib/i18n/locales/en/fetcher.js +71 -0
  106. package/dist/tests/src/lib/i18n/locales/en/index.js +29 -0
  107. package/dist/tests/src/lib/i18n/locales/en/node.js +51 -0
  108. package/dist/tests/src/lib/i18n/locales/en/prompts.js +52 -0
  109. package/dist/tests/src/lib/i18n/locales/en/resources.js +50 -0
  110. package/dist/tests/src/lib/i18n/locales/en/server.js +56 -0
  111. package/dist/tests/src/lib/i18n/locales/en/tools.js +28 -0
  112. package/dist/tests/src/lib/i18n/locales/zh/browser.js +87 -0
  113. package/dist/tests/src/lib/i18n/locales/zh/client.js +66 -0
  114. package/dist/tests/src/lib/i18n/locales/zh/errors.js +28 -0
  115. package/dist/tests/src/lib/i18n/locales/zh/fetcher.js +71 -0
  116. package/dist/tests/src/lib/i18n/locales/zh/index.js +29 -0
  117. package/dist/tests/src/lib/i18n/locales/zh/node.js +51 -0
  118. package/dist/tests/src/lib/i18n/locales/zh/prompts.js +53 -0
  119. package/dist/tests/src/lib/i18n/locales/zh/resources.js +50 -0
  120. package/dist/tests/src/lib/i18n/locales/zh/server.js +57 -0
  121. package/dist/tests/src/lib/i18n/locales/zh/tools.js +28 -0
  122. package/dist/tests/src/lib/i18n/logger.js +114 -0
  123. package/dist/tests/src/lib/logger.js +181 -0
  124. package/dist/tests/test-direct-client.js +0 -0
  125. package/dist/tests/test-i18n.js +530 -0
  126. package/dist/tests/test-mcp-methods.js +1 -1
  127. package/dist/tests/test-mcp.js +0 -0
  128. package/dist/tests/test-mini4k.js +0 -0
  129. package/dist/tests/tests/test-i18n.js +588 -0
  130. package/dist/tests/types.test.js +57 -0
  131. package/dist/tests/utils/ErrorHandler.test.js +144 -0
  132. package/dist/vitest.config.js +29 -0
  133. package/package.json +32 -19
  134. package/dist/src/cli-language.js +0 -78
  135. package/dist/src/lib/example.js +0 -93
  136. package/dist/src/lib/server/logger.js +0 -23
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
  [![Node.js Version](https://img.shields.io/node/v/@lmcc-dev/mult-fetch-mcp-server)](https://nodejs.org/)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue.svg)](https://www.typescriptlang.org/)
7
- [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-1.6.1-brightgreen.svg)](https://github.com/modelcontextprotocol/typescript-sdk)
7
+ [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-1.7.0-brightgreen.svg)](https://github.com/modelcontextprotocol/typescript-sdk)
8
8
  [![GitHub Stars](https://img.shields.io/github/stars/lmcc-dev/mult-fetch-mcp-server)](https://github.com/lmcc-dev/mult-fetch-mcp-server/stargazers)
9
9
  [![GitHub Forks](https://img.shields.io/github/forks/lmcc-dev/mult-fetch-mcp-server)](https://github.com/lmcc-dev/mult-fetch-mcp-server/network/members)
10
10
  [![GitHub Issues](https://img.shields.io/github/issues/lmcc-dev/mult-fetch-mcp-server)](https://github.com/lmcc-dev/mult-fetch-mcp-server/issues)
@@ -13,10 +13,12 @@
13
13
  [![GitHub last commit](https://img.shields.io/github/last-commit/lmcc-dev/mult-fetch-mcp-server)](https://github.com/lmcc-dev/mult-fetch-mcp-server/commits/main)
14
14
  [![GitHub contributors](https://img.shields.io/github/contributors/lmcc-dev/mult-fetch-mcp-server)](https://github.com/lmcc-dev/mult-fetch-mcp-server/graphs/contributors)
15
15
  [![smithery badge](https://smithery.ai/badge/@lmcc-dev/mult-fetch-mcp-server)](https://smithery.ai/server/@lmcc-dev/mult-fetch-mcp-server)
16
+ [![codecov](https://codecov.io/gh/lmcc-dev/mult-fetch-mcp-server/branch/main/graph/badge.svg)](https://codecov.io/gh/lmcc-dev/mult-fetch-mcp-server)
17
+ [![CodeFactor](https://www.codefactor.io/repository/github/lmcc-dev/mult-fetch-mcp-server/badge)](https://www.codefactor.io/repository/github/lmcc-dev/mult-fetch-mcp-server)
18
+
16
19
 
17
20
 
18
21
  <!-- Future badges to consider:
19
- [![codecov](https://codecov.io/gh/lmcc-dev/mult-fetch-mcp-server/branch/main/graph/badge.svg)](https://codecov.io/gh/lmcc-dev/mult-fetch-mcp-server)
20
22
  [![CodeFactor](https://www.codefactor.io/repository/github/lmcc-dev/mult-fetch-mcp-server/badge)](https://www.codefactor.io/repository/github/lmcc-dev/mult-fetch-mcp-server)
21
23
  [![Maintainability](https://api.codeclimate.com/v1/badges/a99a88d28ad37a79dbf6/maintainability)](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
- npm install
94
+ pnpm install
93
95
  ```
94
96
 
95
97
  ### Global Installation
96
98
 
97
99
  ```bash
98
- npm install -g @lmcc-dev/mult-fetch-mcp-server
100
+ pnpm add -g @lmcc-dev/mult-fetch-mcp-server
99
101
  ```
100
102
 
101
- Or use npx to run directly (no installation required):
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
- npm run build
178
+ pnpm run build
177
179
  ```
178
180
 
179
181
  ## Run Server
180
182
 
181
183
  ```bash
182
- npm run server
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
- npm run client <method> <params_json>
196
+ pnpm run client <method> <params_json>
195
197
  # example
196
- npm run client fetch_html '{"url": "https://example.com", "debug": true}'
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
  [![许可证: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
  [![Node.js 版本](https://img.shields.io/node/v/@lmcc-dev/mult-fetch-mcp-server)](https://nodejs.org/)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue.svg)](https://www.typescriptlang.org/)
7
- [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-1.6.1-brightgreen.svg)](https://github.com/modelcontextprotocol/typescript-sdk)
7
+ [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-1.7.0-brightgreen.svg)](https://github.com/modelcontextprotocol/typescript-sdk)
8
8
  [![GitHub Stars](https://img.shields.io/github/stars/lmcc-dev/mult-fetch-mcp-server)](https://github.com/lmcc-dev/mult-fetch-mcp-server/stargazers)
9
9
  [![GitHub Forks](https://img.shields.io/github/forks/lmcc-dev/mult-fetch-mcp-server)](https://github.com/lmcc-dev/mult-fetch-mcp-server/network/members)
10
10
  [![GitHub Issues](https://img.shields.io/github/issues/lmcc-dev/mult-fetch-mcp-server)](https://github.com/lmcc-dev/mult-fetch-mcp-server/issues)
@@ -12,10 +12,11 @@
12
12
  [![npm 下载量](https://img.shields.io/badge/下载量-即将更新-lightgrey)](https://www.npmjs.com/package/@lmcc-dev/mult-fetch-mcp-server)
13
13
  [![GitHub 最后提交](https://img.shields.io/github/last-commit/lmcc-dev/mult-fetch-mcp-server)](https://github.com/lmcc-dev/mult-fetch-mcp-server/commits/main)
14
14
  [![GitHub 贡献者](https://img.shields.io/github/contributors/lmcc-dev/mult-fetch-mcp-server)](https://github.com/lmcc-dev/mult-fetch-mcp-server/graphs/contributors)
15
-
16
- <!-- 未来可考虑添加的徽章:
17
15
  [![codecov](https://codecov.io/gh/lmcc-dev/mult-fetch-mcp-server/branch/main/graph/badge.svg)](https://codecov.io/gh/lmcc-dev/mult-fetch-mcp-server)
18
16
  [![CodeFactor](https://www.codefactor.io/repository/github/lmcc-dev/mult-fetch-mcp-server/badge)](https://www.codefactor.io/repository/github/lmcc-dev/mult-fetch-mcp-server)
17
+
18
+
19
+ <!-- 未来可考虑添加的徽章:
19
20
  [![Maintainability](https://api.codeclimate.com/v1/badges/a99a88d28ad37a79dbf6/maintainability)](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
- npm install
91
+ pnpm install
83
92
  ```
84
93
 
85
94
  ### 全局安装
86
95
 
87
96
  ```bash
88
- npm install -g mult-fetch-mcp-server
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
- npm run build
175
+ pnpm run build
167
176
  ```
168
177
 
169
178
  ## 运行服务器
170
179
 
171
180
  ```bash
172
- npm run server
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
- npm run client <method> <params_json>
193
+ pnpm run client <method> <params_json>
185
194
  # 例如
186
- npm run client fetch_html '{"url": "https://example.com", "debug": true}'
195
+ pnpm run client fetch_html '{"url": "https://example.com", "debug": true}'
187
196
  ```
188
197
 
189
198
  ## 运行测试
@@ -0,0 +1,8 @@
1
+ {
2
+ "timestamp": "2025-03-15T11:54:45.602Z",
3
+ "totalKeys": 406,
4
+ "missingTranslations": [],
5
+ "emptyTranslations": [],
6
+ "placeholderMismatches": [],
7
+ "hasIssues": false
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "timestamp": "2025-03-15T11:54:15.658Z",
3
+ "totalKeys": 406,
4
+ "totalUsedKeys": 406,
5
+ "totalFiles": 195,
6
+ "unusedKeys": [],
7
+ "hasUnusedKeys": false
8
+ }
@@ -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.toLowerCase();
29
+ const errorText = response.content[0].text;
29
30
  if (debug) {
30
- log('fetcher.fetchError', debug, { url: '', error: response.content[0].text }, COMPONENTS.CLIENT);
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 = response.content[0].text.match(/(\b[45]\d\d\b)/);
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 (errorText.includes('403') || errorText.includes('forbidden')) {
38
- log('errors.forbidden', debug, {}, COMPONENTS.CLIENT);
39
- }
40
- else if (errorText.includes('cloudflare')) {
41
- log('errors.cloudflareProtection', debug, {}, COMPONENTS.CLIENT);
42
- }
43
- else if (errorText.includes('captcha')) {
44
- log('errors.captchaRequired', debug, {}, COMPONENTS.CLIENT);
45
- }
46
- else if (errorText.includes('timeout')) {
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 (errorText.includes('socket') || errorText.includes('econnrefused')) {
50
- log('errors.connectionProblem', debug, {}, COMPONENTS.CLIENT);
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.includes('403') ||
54
- errorText.includes('forbidden') ||
55
- errorText.includes('access denied') ||
56
- errorText.includes('cloudflare') ||
57
- errorText.includes('captcha') ||
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.substring(0, 150) + (result.content[0].text.length > 150 ? '...' : '') }, COMPONENTS.CLIENT);
107
+ log('client.fetchFailed', debug, { url, error: result.content[0].text }, COMPONENTS.CLIENT);
110
108
  }
111
109
  else {
112
- const contentLength = result.content[0].text.length;
113
- log('client.fetchSuccess', debug, { length: contentLength }, COMPONENTS.CLIENT);
110
+ log('client.fetchSuccess', debug, { url }, COMPONENTS.CLIENT);
114
111
  }
115
112
  }
116
- // 如果失败并且响应表明需要浏览器模式,且当前不是浏览器模式 (If failed and response indicates browser mode is needed, and current mode is not browser mode)
117
- if (!params.useBrowser && responseRequiresBrowser(result, debug)) {
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: params
127
- });
128
- // 在调试模式下打印浏览器模式的响应结果摘要 (Print browser mode response result summary in debug mode)
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
- if (debug) {
155
- if (result.isError) {
156
- log('client.fetchFailed', debug, { error: result.content[0].text.substring(0, 150) + (result.content[0].text.length > 150 ? '...' : '') }, COMPONENTS.CLIENT);
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, heapTotal, rss }, COMPONENTS.BROWSER_FETCH);
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: this.getDomain(url) }, COMPONENTS.BROWSER_FETCH);
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, { debug }, COMPONENTS.BROWSER_FETCH);
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, { debug }, COMPONENTS.BROWSER_FETCH);
494
+ log('browser.continuingWithoutBypass', debug, {}, COMPONENTS.BROWSER_FETCH);
495
495
  }
496
496
  // 等待选择器
497
- log('browser.waitingForSelector', debug, { selector: waitForSelector, debug }, COMPONENTS.BROWSER_FETCH);
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, debug }, COMPONENTS.BROWSER_FETCH);
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, { debug }, COMPONENTS.BROWSER_FETCH);
506
+ log('browser.scrolling', debug, {}, COMPONENTS.BROWSER_FETCH);
507
507
  await this.autoScroll(page, debug);
508
508
  }
509
509
  // 获取页面内容
510
- log('browser.gettingContent', debug, { debug }, COMPONENTS.BROWSER_FETCH);
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, { debug }, COMPONENTS.BROWSER_FETCH);
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, debug }, COMPONENTS.BROWSER_FETCH);
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, { debug }, COMPONENTS.BROWSER_FETCH);
527
+ log('browser.contentTruncated', debug, {}, COMPONENTS.BROWSER_FETCH);
528
528
  }
529
529
  // 关闭页面
530
530
  await page.close();
531
- log('browser.pageClosed', debug, { debug }, COMPONENTS.BROWSER_FETCH);
531
+ log('browser.pageClosed', debug, {}, COMPONENTS.BROWSER_FETCH);
532
532
  // 如果需要关闭浏览器
533
533
  if (closeBrowser) {
534
534
  await this.closeBrowser(debug);