@lmcc-dev/mult-fetch-mcp-server 1.1.0 → 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 (216) hide show
  1. package/README.md +8 -8
  2. package/README.zh.md +16 -8
  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 +50 -35
  6. package/dist/src/index.js +0 -0
  7. package/dist/src/lib/BrowserFetcher.js +12 -12
  8. package/dist/src/lib/NodeFetcher.js +22 -22
  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 +488 -119
  33. package/dist/src/lib/i18n/locales/en/browser.js +67 -57
  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 +8 -2
  38. package/dist/src/lib/i18n/locales/en/index.js +10 -8
  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 -55
  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 +71 -62
  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 +36 -30
  49. package/dist/src/lib/i18n/locales/zh/index.js +10 -8
  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 +52 -55
  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 +2 -2
  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 +46 -10
  63. package/dist/src/lib/utils/ErrorHandler.js +125 -0
  64. package/dist/src/mcp-server.js +0 -0
  65. package/dist/src/test-i18n.js +139 -0
  66. package/dist/tests/BrowserFetcher.test.js +0 -0
  67. package/dist/tests/NodeFetcher.test.js +0 -0
  68. package/dist/tests/client.test.js +42 -81
  69. package/dist/tests/fetch.test.js +70 -0
  70. package/dist/tests/fetchers/Fetcher.test.js +108 -0
  71. package/dist/tests/fetchers/browser/BrowserFetcher.test.js +195 -0
  72. package/dist/tests/fetchers/browser/BrowserInstance.test.js +163 -0
  73. package/dist/tests/fetchers/node/NodeFetcher.test.js +211 -0
  74. package/dist/tests/i18n-missing-keys.js +364 -0
  75. package/dist/tests/i18n-remove-unused-keys.js +236 -0
  76. package/dist/tests/i18n-test-report.json +2004 -0
  77. package/dist/tests/i18n-unused-keys.js +425 -0
  78. package/dist/tests/i18n.test.js +6 -7
  79. package/dist/tests/logger.test.js +14 -13
  80. package/dist/tests/mcp-server.test.js +7 -7
  81. package/dist/tests/server/browser.test.js +25 -21
  82. package/dist/tests/server/fetcher.test.js +58 -101
  83. package/dist/tests/server/index.test.js +30 -30
  84. package/dist/tests/server/prompts.test.js +36 -33
  85. package/dist/tests/server/resources.test.js +120 -84
  86. package/dist/tests/server/tools.test.js +7 -6
  87. package/dist/tests/setup.js +36 -0
  88. package/dist/tests/src/lib/i18n/index.js +108 -0
  89. package/dist/tests/src/lib/i18n/keys/base.js +47 -0
  90. package/dist/tests/src/lib/i18n/keys/browser.js +93 -0
  91. package/dist/tests/src/lib/i18n/keys/client.js +70 -0
  92. package/dist/tests/src/lib/i18n/keys/errors.js +34 -0
  93. package/dist/tests/src/lib/i18n/keys/fetcher.js +84 -0
  94. package/dist/tests/src/lib/i18n/keys/index.js +31 -0
  95. package/dist/tests/src/lib/i18n/keys/node.js +56 -0
  96. package/dist/tests/src/lib/i18n/keys/prompts.js +82 -0
  97. package/dist/tests/src/lib/i18n/keys/resources.js +50 -0
  98. package/dist/tests/src/lib/i18n/keys/server.js +64 -0
  99. package/dist/tests/src/lib/i18n/keys/tools.js +34 -0
  100. package/dist/tests/src/lib/i18n/locales/en/browser.js +88 -0
  101. package/dist/tests/src/lib/i18n/locales/en/client.js +66 -0
  102. package/dist/tests/src/lib/i18n/locales/en/errors.js +28 -0
  103. package/dist/tests/src/lib/i18n/locales/en/fetcher.js +71 -0
  104. package/dist/tests/src/lib/i18n/locales/en/index.js +29 -0
  105. package/dist/tests/src/lib/i18n/locales/en/node.js +51 -0
  106. package/dist/tests/src/lib/i18n/locales/en/prompts.js +52 -0
  107. package/dist/tests/src/lib/i18n/locales/en/resources.js +50 -0
  108. package/dist/tests/src/lib/i18n/locales/en/server.js +56 -0
  109. package/dist/tests/src/lib/i18n/locales/en/tools.js +28 -0
  110. package/dist/tests/src/lib/i18n/locales/zh/browser.js +87 -0
  111. package/dist/tests/src/lib/i18n/locales/zh/client.js +66 -0
  112. package/dist/tests/src/lib/i18n/locales/zh/errors.js +28 -0
  113. package/dist/tests/src/lib/i18n/locales/zh/fetcher.js +71 -0
  114. package/dist/tests/src/lib/i18n/locales/zh/index.js +29 -0
  115. package/dist/tests/src/lib/i18n/locales/zh/node.js +51 -0
  116. package/dist/tests/src/lib/i18n/locales/zh/prompts.js +53 -0
  117. package/dist/tests/src/lib/i18n/locales/zh/resources.js +50 -0
  118. package/dist/tests/src/lib/i18n/locales/zh/server.js +57 -0
  119. package/dist/tests/src/lib/i18n/locales/zh/tools.js +28 -0
  120. package/dist/tests/src/lib/i18n/logger.js +114 -0
  121. package/dist/tests/src/lib/logger.js +181 -0
  122. package/dist/tests/test-direct-client.js +0 -0
  123. package/dist/tests/test-i18n.js +530 -0
  124. package/dist/tests/test-mcp-methods.js +1 -1
  125. package/dist/tests/test-mcp.js +0 -0
  126. package/dist/tests/test-mini4k.js +0 -0
  127. package/dist/tests/tests/test-i18n.js +588 -0
  128. package/dist/tests/types.test.js +1 -1
  129. package/dist/tests/utils/ErrorHandler.test.js +144 -0
  130. package/dist/vitest.config.js +29 -0
  131. package/package.json +31 -27
  132. package/dist/src/cli-language.js +0 -78
  133. package/dist/src/client.d.ts +0 -6
  134. package/dist/src/client.js.map +0 -1
  135. package/dist/src/index.d.ts +0 -15
  136. package/dist/src/index.js.map +0 -1
  137. package/dist/src/lib/BrowserFetcher.d.ts +0 -175
  138. package/dist/src/lib/BrowserFetcher.js.map +0 -1
  139. package/dist/src/lib/NodeFetcher.d.ts +0 -92
  140. package/dist/src/lib/NodeFetcher.js.map +0 -1
  141. package/dist/src/lib/example.js +0 -93
  142. package/dist/src/lib/i18n/index.js.map +0 -1
  143. package/dist/src/lib/i18n/locales/en/browser.d.ts +0 -61
  144. package/dist/src/lib/i18n/locales/en/browser.js.map +0 -1
  145. package/dist/src/lib/i18n/locales/en/client.d.ts +0 -39
  146. package/dist/src/lib/i18n/locales/en/client.js.map +0 -1
  147. package/dist/src/lib/i18n/locales/en/errors.d.ts +0 -17
  148. package/dist/src/lib/i18n/locales/en/errors.js.map +0 -1
  149. package/dist/src/lib/i18n/locales/en/fetcher.d.ts +0 -66
  150. package/dist/src/lib/i18n/locales/en/fetcher.js.map +0 -1
  151. package/dist/src/lib/i18n/locales/en/index.d.ts +0 -344
  152. package/dist/src/lib/i18n/locales/en/index.js.map +0 -1
  153. package/dist/src/lib/i18n/locales/en/node.d.ts +0 -41
  154. package/dist/src/lib/i18n/locales/en/node.js.map +0 -1
  155. package/dist/src/lib/i18n/locales/en/prompts.d.ts +0 -65
  156. package/dist/src/lib/i18n/locales/en/prompts.js.map +0 -1
  157. package/dist/src/lib/i18n/locales/en/resources.d.ts +0 -41
  158. package/dist/src/lib/i18n/locales/en/resources.js.map +0 -1
  159. package/dist/src/lib/i18n/locales/en/server.d.ts +0 -30
  160. package/dist/src/lib/i18n/locales/en/server.js.map +0 -1
  161. package/dist/src/lib/i18n/locales/en/tools.d.ts +0 -24
  162. package/dist/src/lib/i18n/locales/en/tools.js.map +0 -1
  163. package/dist/src/lib/i18n/locales/zh/browser.d.ts +0 -61
  164. package/dist/src/lib/i18n/locales/zh/browser.js.map +0 -1
  165. package/dist/src/lib/i18n/locales/zh/client.d.ts +0 -38
  166. package/dist/src/lib/i18n/locales/zh/client.js.map +0 -1
  167. package/dist/src/lib/i18n/locales/zh/errors.d.ts +0 -17
  168. package/dist/src/lib/i18n/locales/zh/errors.js.map +0 -1
  169. package/dist/src/lib/i18n/locales/zh/fetcher.d.ts +0 -66
  170. package/dist/src/lib/i18n/locales/zh/fetcher.js.map +0 -1
  171. package/dist/src/lib/i18n/locales/zh/index.d.ts +0 -343
  172. package/dist/src/lib/i18n/locales/zh/index.js.map +0 -1
  173. package/dist/src/lib/i18n/locales/zh/node.d.ts +0 -41
  174. package/dist/src/lib/i18n/locales/zh/node.js.map +0 -1
  175. package/dist/src/lib/i18n/locales/zh/prompts.d.ts +0 -65
  176. package/dist/src/lib/i18n/locales/zh/prompts.js.map +0 -1
  177. package/dist/src/lib/i18n/locales/zh/resources.d.ts +0 -41
  178. package/dist/src/lib/i18n/locales/zh/resources.js.map +0 -1
  179. package/dist/src/lib/i18n/locales/zh/server.d.ts +0 -30
  180. package/dist/src/lib/i18n/locales/zh/server.js.map +0 -1
  181. package/dist/src/lib/i18n/locales/zh/tools.d.ts +0 -24
  182. package/dist/src/lib/i18n/locales/zh/tools.js.map +0 -1
  183. package/dist/src/lib/i18n/logger.d.ts +0 -38
  184. package/dist/src/lib/i18n/logger.js.map +0 -1
  185. package/dist/src/lib/logger.d.ts +0 -32
  186. package/dist/src/lib/logger.js.map +0 -1
  187. package/dist/src/lib/server/browser.d.ts +0 -34
  188. package/dist/src/lib/server/browser.js.map +0 -1
  189. package/dist/src/lib/server/fetcher.d.ts +0 -20
  190. package/dist/src/lib/server/fetcher.js.map +0 -1
  191. package/dist/src/lib/server/index.d.ts +0 -10
  192. package/dist/src/lib/server/index.js.map +0 -1
  193. package/dist/src/lib/server/logger.js +0 -23
  194. package/dist/src/lib/server/prompts.d.ts +0 -11
  195. package/dist/src/lib/server/prompts.js.map +0 -1
  196. package/dist/src/lib/server/resources.d.ts +0 -11
  197. package/dist/src/lib/server/resources.js.map +0 -1
  198. package/dist/src/lib/server/tools.d.ts +0 -12
  199. package/dist/src/lib/server/tools.js.map +0 -1
  200. package/dist/src/lib/server/types.d.ts +0 -71
  201. package/dist/src/lib/server/types.js.map +0 -1
  202. package/dist/src/lib/types.d.ts +0 -119
  203. package/dist/src/lib/types.js.map +0 -1
  204. package/dist/src/mcp-server.d.ts +0 -6
  205. package/dist/src/mcp-server.js.map +0 -1
  206. package/dist/tests/jest.setup.d.ts +0 -6
  207. package/dist/tests/jest.setup.js +0 -30
  208. package/dist/tests/jest.setup.js.map +0 -1
  209. package/dist/tests/test-direct-client.d.ts +0 -6
  210. package/dist/tests/test-direct-client.js.map +0 -1
  211. package/dist/tests/test-mcp-methods.d.ts +0 -6
  212. package/dist/tests/test-mcp-methods.js.map +0 -1
  213. package/dist/tests/test-mcp.d.ts +0 -6
  214. package/dist/tests/test-mcp.js.map +0 -1
  215. package/dist/tests/test-mini4k.d.ts +0 -6
  216. package/dist/tests/test-mini4k.js.map +0 -1
@@ -3,8 +3,7 @@
3
3
  * Co-Author: AI Assistant (Claude)
4
4
  * Description: This code was collaboratively developed by Martin and AI Assistant.
5
5
  */
6
- import { BrowserFetcher } from '../BrowserFetcher.js';
7
- import { NodeFetcher } from '../NodeFetcher.js';
6
+ import { Fetcher } from '../fetch.js';
8
7
  import { log, COMPONENTS } from '../logger.js';
9
8
  import { initializeBrowser, closeBrowserInstance, shouldSwitchToBrowser } from './browser.js';
10
9
  /**
@@ -32,13 +31,13 @@ export async function fetchWithAutoDetect(params, type) {
32
31
  // 根据类型选择合适的浏览器获取方法 (Choose appropriate browser fetching method based on type)
33
32
  switch (type) {
34
33
  case 'html':
35
- return await BrowserFetcher.html(params);
34
+ return await Fetcher.html(params);
36
35
  case 'json':
37
- return await BrowserFetcher.json(params);
36
+ return await Fetcher.json(params);
38
37
  case 'txt':
39
- return await BrowserFetcher.txt(params);
38
+ return await Fetcher.txt(params);
40
39
  case 'markdown':
41
- return await BrowserFetcher.markdown(params);
40
+ return await Fetcher.markdown(params);
42
41
  }
43
42
  }
44
43
  else {
@@ -50,36 +49,16 @@ export async function fetchWithAutoDetect(params, type) {
50
49
  // 根据类型选择合适的标准获取方法 (Choose appropriate standard fetching method based on type)
51
50
  switch (type) {
52
51
  case 'html': {
53
- const result = await NodeFetcher.html(params);
54
- // 转换为统一格式 (Convert to unified format)
55
- return {
56
- content: [{ type: 'text', text: result.html }],
57
- isError: false
58
- };
52
+ return await Fetcher.html(params);
59
53
  }
60
54
  case 'json': {
61
- const result = await NodeFetcher.json(params);
62
- // 转换为统一格式 (Convert to unified format)
63
- return {
64
- content: [{ type: 'text', text: typeof result.json === 'string' ? result.json : JSON.stringify(result.json, null, 2) }],
65
- isError: false
66
- };
55
+ return await Fetcher.json(params);
67
56
  }
68
57
  case 'txt': {
69
- const result = await NodeFetcher.txt(params);
70
- // 转换为统一格式 (Convert to unified format)
71
- return {
72
- content: [{ type: 'text', text: result.text }],
73
- isError: false
74
- };
58
+ return await Fetcher.txt(params);
75
59
  }
76
60
  case 'markdown': {
77
- const result = await NodeFetcher.markdown(params);
78
- // 转换为统一格式 (Convert to unified format)
79
- return {
80
- content: [{ type: 'text', text: result.markdown }],
81
- isError: false
82
- };
61
+ return await Fetcher.markdown(params);
83
62
  }
84
63
  }
85
64
  }
@@ -97,13 +76,13 @@ export async function fetchWithAutoDetect(params, type) {
97
76
  // 根据类型选择合适的浏览器获取方法
98
77
  switch (type) {
99
78
  case 'html':
100
- return await BrowserFetcher.html(params);
79
+ return await Fetcher.html(params);
101
80
  case 'json':
102
- return await BrowserFetcher.json(params);
81
+ return await Fetcher.json(params);
103
82
  case 'txt':
104
- return await BrowserFetcher.txt(params);
83
+ return await Fetcher.txt(params);
105
84
  case 'markdown':
106
- return await BrowserFetcher.markdown(params);
85
+ return await Fetcher.markdown(params);
107
86
  }
108
87
  }
109
88
  // 如果不需要切换到浏览器模式,则抛出原始错误
@@ -3,8 +3,8 @@
3
3
  * Co-Author: AI Assistant (Claude)
4
4
  * Description: This code was collaboratively developed by Martin and AI Assistant.
5
5
  */
6
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
7
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
7
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
8
8
  import { log, COMPONENTS } from '../logger.js';
9
9
  import { closeBrowserInstance } from './browser.js';
10
10
  import { registerTools } from './tools.js';
@@ -3,7 +3,7 @@
3
3
  * Co-Author: AI Assistant (Claude)
4
4
  * Description: This code was collaboratively developed by Martin and AI Assistant.
5
5
  */
6
- import { ListPromptsRequestSchema, GetPromptRequestSchema } from "@modelcontextprotocol/sdk/types.js";
6
+ import { ListPromptsRequestSchema, GetPromptRequestSchema } from '@modelcontextprotocol/sdk/types.js';
7
7
  import { log, COMPONENTS } from '../logger.js';
8
8
  import { t } from '../i18n/index.js';
9
9
  // 定义提示模板 (Define prompt templates)
@@ -3,7 +3,7 @@
3
3
  * Co-Author: AI Assistant (Claude)
4
4
  * Description: This code was collaboratively developed by Martin and AI Assistant.
5
5
  */
6
- import { ListResourcesRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
6
+ import { ListResourcesRequestSchema, ReadResourceRequestSchema } from '@modelcontextprotocol/sdk/types.js';
7
7
  import { log, getLogFilePath, clearLogFile, COMPONENTS } from '../logger.js';
8
8
  import fs from 'fs';
9
9
  import path from 'path';
@@ -3,7 +3,7 @@
3
3
  * Co-Author: AI Assistant (Claude)
4
4
  * Description: This code was collaboratively developed by Martin and AI Assistant.
5
5
  */
6
- import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
6
+ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
7
7
  import { log, COMPONENTS } from '../logger.js';
8
8
  import { fetchWithAutoDetect } from './fetcher.js';
9
9
  import { closeBrowserInstance } from './browser.js';
@@ -312,18 +312,20 @@ function registerToolCallHandler(server) {
312
312
  // 处理不同类型的获取请求 (Handle different types of fetch requests)
313
313
  if (name === 'fetch_html' || name === 'fetch_json' || name === 'fetch_txt' || name === 'fetch_markdown') {
314
314
  const result = await handleFetchRequest(name, args, debug);
315
+ // 直接返回符合 MCP SDK 要求的格式
315
316
  return result;
316
317
  }
317
318
  else {
318
319
  // 未知工具 (Unknown tool)
319
320
  log('tools.unknownTool', debug, { name }, COMPONENTS.SERVER);
320
321
  return {
321
- isError: true,
322
322
  content: [
323
323
  {
324
+ type: "text",
324
325
  text: `Unknown tool: ${name}`
325
326
  }
326
- ]
327
+ ],
328
+ isError: true
327
329
  };
328
330
  }
329
331
  }
@@ -331,12 +333,13 @@ function registerToolCallHandler(server) {
331
333
  // 处理错误 (Handle error)
332
334
  log('tools.callError', debug, { name, error: error.message }, COMPONENTS.SERVER);
333
335
  return {
334
- isError: true,
335
336
  content: [
336
337
  {
338
+ type: "text",
337
339
  text: error.message
338
340
  }
339
- ]
341
+ ],
342
+ isError: true
340
343
  };
341
344
  }
342
345
  finally {
@@ -359,12 +362,13 @@ async function handleFetchRequest(name, args, debug) {
359
362
  if (!args.url) {
360
363
  log('tools.missingUrl', debug, {}, COMPONENTS.SERVER);
361
364
  return {
362
- isError: true,
363
365
  content: [
364
366
  {
367
+ type: "text",
365
368
  text: "URL parameter is required"
366
369
  }
367
- ]
370
+ ],
371
+ isError: true
368
372
  };
369
373
  }
370
374
  // 记录请求 (Log request)
@@ -378,18 +382,50 @@ async function handleFetchRequest(name, args, debug) {
378
382
  // 根据工具名称确定内容类型 (Determine content type based on tool name)
379
383
  const type = name.replace('fetch_', '');
380
384
  const result = await fetchWithAutoDetect(params, type);
381
- return result;
385
+ // 确保返回标准结构体 (Ensure returning standard structure)
386
+ if (result.isError) {
387
+ // 确保错误内容有正确的类型 (Ensure error content has correct type)
388
+ if (!result.content[0].type) {
389
+ result.content[0].type = "text";
390
+ }
391
+ }
392
+ else {
393
+ // 对于 JSON 类型,验证内容是否为有效的 JSON (For JSON type, validate if content is valid JSON)
394
+ if (type === 'json') {
395
+ try {
396
+ // 尝试解析 JSON (Try to parse JSON)
397
+ JSON.parse(result.content[0].text);
398
+ }
399
+ catch (jsonError) {
400
+ // JSON 解析失败,但仍然返回原始内容 (JSON parsing failed, but still return original content)
401
+ log('tools.jsonParseWarning', debug, { error: jsonError.message }, COMPONENTS.SERVER);
402
+ // 不将 isError 设置为 true,保持原始结果
403
+ // (Don't set isError to true, keep original result)
404
+ }
405
+ }
406
+ // 确保成功内容有正确的类型 (Ensure success content has correct type)
407
+ if (!result.content[0].type) {
408
+ result.content[0].type = "text";
409
+ }
410
+ }
411
+ // 将FetchResponse转换为符合MCP SDK要求的格式
412
+ return {
413
+ content: result.content,
414
+ isError: result.isError
415
+ };
382
416
  }
383
417
  catch (error) {
384
418
  // 处理错误 (Handle error)
385
419
  log('tools.fetchError', debug, { url: args.url, error: error.message }, COMPONENTS.SERVER);
420
+ // 确保返回标准结构体 (Ensure returning standard structure)
386
421
  return {
387
- isError: true,
388
422
  content: [
389
423
  {
424
+ type: "text",
390
425
  text: `Error fetching ${args.url}: ${error.message}`
391
426
  }
392
- ]
427
+ ],
428
+ isError: true
393
429
  };
394
430
  }
395
431
  }
@@ -0,0 +1,125 @@
1
+ /*
2
+ * Author: Martin <lmccc.dev@gmail.com>
3
+ * Co-Author: AI Assistant (Claude)
4
+ * Description: This code was collaboratively developed by Martin and AI Assistant.
5
+ */
6
+ import { isAccessDeniedError, isNetworkError } from './errorDetection.js';
7
+ import { log, COMPONENTS } from '../logger.js';
8
+ /**
9
+ * 错误类型枚举
10
+ * (Error type enumeration)
11
+ */
12
+ export var ErrorType;
13
+ (function (ErrorType) {
14
+ ErrorType["NETWORK"] = "network";
15
+ ErrorType["ACCESS_DENIED"] = "access_denied";
16
+ ErrorType["TIMEOUT"] = "timeout";
17
+ ErrorType["PARSE"] = "parse";
18
+ ErrorType["VALIDATION"] = "validation";
19
+ ErrorType["BROWSER"] = "browser";
20
+ ErrorType["UNKNOWN"] = "unknown";
21
+ })(ErrorType || (ErrorType = {}));
22
+ /**
23
+ * 错误处理器类,用于统一处理和分类错误
24
+ * (Error handler class for unified error handling and classification)
25
+ */
26
+ export class ErrorHandler {
27
+ /**
28
+ * 处理错误并返回格式化的错误消息
29
+ * (Handle error and return formatted error message)
30
+ *
31
+ * @param error 捕获的错误对象 (Caught error object)
32
+ * @param component 组件名称,用于日志 (Component name for logging)
33
+ * @param debug 是否启用调试模式 (Whether debug mode is enabled)
34
+ * @param context 错误上下文信息 (Error context information)
35
+ * @returns 格式化的错误消息 (Formatted error message)
36
+ */
37
+ static handleError(error, component = COMPONENTS.SERVER, debug = false, context = {}) {
38
+ const errorType = this.classifyError(error);
39
+ const errorMessage = this.getErrorMessage(error);
40
+ // 记录错误日志
41
+ // (Log error)
42
+ log(`errors.${errorType}_error`, debug, {
43
+ error: errorMessage,
44
+ ...context
45
+ }, component);
46
+ return errorMessage;
47
+ }
48
+ /**
49
+ * 分类错误类型
50
+ * (Classify error type)
51
+ *
52
+ * @param error 捕获的错误对象 (Caught error object)
53
+ * @returns 错误类型 (Error type)
54
+ */
55
+ static classifyError(error) {
56
+ const errorMessage = this.getErrorMessage(error);
57
+ // 先检查超时错误 (Check timeout errors first)
58
+ if (errorMessage.toLowerCase().includes('timeout')) {
59
+ return ErrorType.TIMEOUT;
60
+ }
61
+ if (isNetworkError(errorMessage)) {
62
+ return ErrorType.NETWORK;
63
+ }
64
+ if (isAccessDeniedError(errorMessage)) {
65
+ return ErrorType.ACCESS_DENIED;
66
+ }
67
+ if (errorMessage.toLowerCase().includes('parse') ||
68
+ errorMessage.toLowerCase().includes('json') ||
69
+ errorMessage.toLowerCase().includes('syntax')) {
70
+ return ErrorType.PARSE;
71
+ }
72
+ if (errorMessage.toLowerCase().includes('browser') ||
73
+ errorMessage.toLowerCase().includes('puppeteer') ||
74
+ errorMessage.toLowerCase().includes('page') ||
75
+ errorMessage.toLowerCase().includes('chrome')) {
76
+ return ErrorType.BROWSER;
77
+ }
78
+ if (errorMessage.toLowerCase().includes('valid') ||
79
+ errorMessage.toLowerCase().includes('schema') ||
80
+ errorMessage.toLowerCase().includes('type')) {
81
+ return ErrorType.VALIDATION;
82
+ }
83
+ return ErrorType.UNKNOWN;
84
+ }
85
+ /**
86
+ * 获取错误消息
87
+ * (Get error message)
88
+ *
89
+ * @param error 捕获的错误对象 (Caught error object)
90
+ * @returns 错误消息字符串 (Error message string)
91
+ */
92
+ static getErrorMessage(error) {
93
+ if (error instanceof Error) {
94
+ return error.message;
95
+ }
96
+ if (typeof error === 'string') {
97
+ return error;
98
+ }
99
+ if (error && typeof error === 'object') {
100
+ if ('message' in error && typeof error.message === 'string') {
101
+ return error.message;
102
+ }
103
+ try {
104
+ return JSON.stringify(error);
105
+ }
106
+ catch {
107
+ return String(error);
108
+ }
109
+ }
110
+ return String(error);
111
+ }
112
+ /**
113
+ * 创建带有错误类型的错误对象
114
+ * (Create error object with error type)
115
+ *
116
+ * @param message 错误消息 (Error message)
117
+ * @param type 错误类型 (Error type)
118
+ * @returns 带有类型的错误对象 (Error object with type)
119
+ */
120
+ static createError(message, type = ErrorType.UNKNOWN) {
121
+ const error = new Error(message);
122
+ error.type = type;
123
+ return error;
124
+ }
125
+ }
File without changes
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Author: Martin <lmccc.dev@gmail.com>
3
+ * Co-Author: AI Assistant (Claude)
4
+ * Description: This code was collaboratively developed by Martin and AI Assistant.
5
+ */
6
+ // 测试国际化功能 (Test internationalization functionality)
7
+ import { log, COMPONENTS, clearTranslationCache } from './lib/logger.js';
8
+ import { t, changeLanguage, getCurrentLanguage } from './lib/i18n/index.js';
9
+ /**
10
+ * 测试翻译键 (Test translation keys)
11
+ * @param keys 要测试的键数组 (Array of keys to test)
12
+ * @param language 语言 (Language)
13
+ */
14
+ function testKeys(keys, language) {
15
+ console.log(`\n=== 测试 ${language} 翻译 (Testing ${language} translation) ===`);
16
+ for (const key of keys) {
17
+ try {
18
+ const translated = t(key);
19
+ console.log(`Key: ${key}`);
20
+ console.log(`Translation: ${translated}`);
21
+ console.log('---');
22
+ }
23
+ catch (error) {
24
+ console.error(`Error translating key: ${key}`);
25
+ console.error(error);
26
+ console.log('---');
27
+ }
28
+ }
29
+ }
30
+ /**
31
+ * 测试日志函数 (Test log function)
32
+ * @param keys 要测试的键数组 (Array of keys to test)
33
+ * @param component 组件名称 (Component name)
34
+ */
35
+ function testLogFunction(keys, component) {
36
+ console.log(`\n=== 测试日志函数 (Testing log function) ===`);
37
+ for (const key of keys) {
38
+ log(key, true, {}, component);
39
+ }
40
+ }
41
+ /**
42
+ * 测试带参数的翻译 (Test translation with parameters)
43
+ * @param keys 要测试的键数组 (Array of keys to test)
44
+ * @param params 参数对象 (Parameters object)
45
+ */
46
+ function testWithParams(keys, params) {
47
+ console.log(`\n=== 测试带参数的翻译 (Testing translation with parameters) ===`);
48
+ for (const key of keys) {
49
+ try {
50
+ const translated = t(key, params);
51
+ console.log(`Key: ${key}`);
52
+ console.log(`Params: ${JSON.stringify(params)}`);
53
+ console.log(`Translation: ${translated}`);
54
+ console.log('---');
55
+ }
56
+ catch (error) {
57
+ console.error(`Error translating key with params: ${key}`);
58
+ console.error(error);
59
+ console.log('---');
60
+ }
61
+ }
62
+ }
63
+ /**
64
+ * 测试翻译缓存 (Test translation cache)
65
+ * @param key 要测试的键 (Key to test)
66
+ * @param iterations 迭代次数 (Number of iterations)
67
+ */
68
+ function testTranslationCache(key, iterations) {
69
+ console.log(`\n=== 测试翻译缓存 (Testing translation cache) ===`);
70
+ console.log(`Key: ${key}`);
71
+ console.log(`Iterations: ${iterations}`);
72
+ // 清除翻译缓存 (Clear translation cache)
73
+ clearTranslationCache();
74
+ // 测试不使用缓存的性能 (Test performance without cache)
75
+ console.log('Without cache:');
76
+ const startWithoutCache = Date.now();
77
+ for (let i = 0; i < iterations; i++) {
78
+ t(key);
79
+ }
80
+ const endWithoutCache = Date.now();
81
+ console.log(`Time: ${endWithoutCache - startWithoutCache}ms`);
82
+ // 测试使用缓存的性能 (Test performance with cache)
83
+ console.log('With cache:');
84
+ const startWithCache = Date.now();
85
+ for (let i = 0; i < iterations; i++) {
86
+ log(key, true, {}, COMPONENTS.SERVER);
87
+ }
88
+ const endWithCache = Date.now();
89
+ console.log(`Time: ${endWithCache - startWithCache}ms`);
90
+ console.log('---');
91
+ }
92
+ /**
93
+ * 设置环境变量 (Set environment variable)
94
+ * @param name 环境变量名称 (Environment variable name)
95
+ * @param value 环境变量值 (Environment variable value)
96
+ */
97
+ function setEnv(name, value) {
98
+ process.env[name] = value;
99
+ console.log(`Set environment variable ${name}=${value}`);
100
+ }
101
+ /**
102
+ * 主测试函数 (Main test function)
103
+ */
104
+ async function testI18n() {
105
+ console.log('=== 测试国际化功能 (Testing internationalization functionality) ===');
106
+ // 测试简单的键 (Test simple keys)
107
+ const simpleKeys = [
108
+ 'server.starting',
109
+ 'server.started',
110
+ 'server.stopping',
111
+ 'server.stopped'
112
+ ];
113
+ // 确保 MCP_LANG 环境变量设置为英文 (Ensure MCP_LANG environment variable is set to English)
114
+ setEnv('MCP_LANG', 'en');
115
+ // 测试英文翻译 (Test English translation)
116
+ changeLanguage('en');
117
+ console.log(`Current language: ${getCurrentLanguage()}`);
118
+ testKeys(simpleKeys, 'English');
119
+ // 测试日志函数 (Test log function)
120
+ testLogFunction(simpleKeys, COMPONENTS.SERVER);
121
+ // 测试带参数的翻译 (Test translation with parameters)
122
+ testWithParams(['server.listeningOn'], { port: 8080 });
123
+ // 测试翻译缓存 (Test translation cache)
124
+ testTranslationCache('server.starting', 10);
125
+ // 确保 MCP_LANG 环境变量设置为中文 (Ensure MCP_LANG environment variable is set to Chinese)
126
+ setEnv('MCP_LANG', 'zh');
127
+ // 测试中文翻译 (Test Chinese translation)
128
+ changeLanguage('zh');
129
+ console.log(`Current language: ${getCurrentLanguage()}`);
130
+ testKeys(simpleKeys, 'Chinese');
131
+ // 测试日志函数 (Test log function)
132
+ testLogFunction(simpleKeys, COMPONENTS.SERVER);
133
+ // 测试带参数的翻译 (Test translation with parameters)
134
+ testWithParams(['server.listeningOn'], { port: 8080 });
135
+ // 测试翻译缓存 (Test translation cache)
136
+ testTranslationCache('server.starting', 10);
137
+ }
138
+ // 运行测试 (Run test)
139
+ testI18n().catch(console.error);
File without changes
File without changes