@lmcc-dev/mult-fetch-mcp-server 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/README.zh.md +16 -8
- package/dist/i18n-test-report.json +8 -0
- package/dist/i18n-unused-keys-report.json +8 -0
- package/dist/src/client.js +70 -37
- package/dist/src/index.js +0 -0
- package/dist/src/lib/BrowserFetcher.js +12 -12
- package/dist/src/lib/NodeFetcher.js +22 -22
- 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 +488 -119
- package/dist/src/lib/i18n/locales/en/browser.js +67 -57
- 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 +8 -2
- package/dist/src/lib/i18n/locales/en/index.js +10 -8
- 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 -55
- 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 +71 -62
- 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 +36 -30
- package/dist/src/lib/i18n/locales/zh/index.js +10 -8
- 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 +52 -55
- 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 +42 -10
- package/dist/src/lib/server/fetcher.js +87 -37
- 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 +46 -10
- package/dist/src/lib/utils/ErrorHandler.js +125 -0
- package/dist/src/mcp-server.js +0 -0
- package/dist/src/test-i18n.js +139 -0
- package/dist/tests/BrowserFetcher.test.js +0 -0
- package/dist/tests/NodeFetcher.test.js +0 -0
- package/dist/tests/client.test.js +42 -81
- 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 +6 -7
- package/dist/tests/logger.test.js +14 -13
- package/dist/tests/mcp-server.test.js +7 -7
- package/dist/tests/server/browser.test.js +25 -21
- package/dist/tests/server/fetcher.test.js +58 -101
- package/dist/tests/server/index.test.js +30 -30
- package/dist/tests/server/prompts.test.js +36 -33
- package/dist/tests/server/resources.test.js +120 -84
- package/dist/tests/server/tools.test.js +7 -6
- 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 +1 -1
- package/dist/tests/utils/ErrorHandler.test.js +144 -0
- package/dist/vitest.config.js +29 -0
- package/package.json +31 -27
- package/dist/src/cli-language.js +0 -78
- package/dist/src/client.d.ts +0 -6
- package/dist/src/client.js.map +0 -1
- package/dist/src/index.d.ts +0 -15
- package/dist/src/index.js.map +0 -1
- package/dist/src/lib/BrowserFetcher.d.ts +0 -175
- package/dist/src/lib/BrowserFetcher.js.map +0 -1
- package/dist/src/lib/NodeFetcher.d.ts +0 -92
- package/dist/src/lib/NodeFetcher.js.map +0 -1
- package/dist/src/lib/example.js +0 -93
- package/dist/src/lib/i18n/index.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/browser.d.ts +0 -61
- package/dist/src/lib/i18n/locales/en/browser.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/client.d.ts +0 -39
- package/dist/src/lib/i18n/locales/en/client.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/errors.d.ts +0 -17
- package/dist/src/lib/i18n/locales/en/errors.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/fetcher.d.ts +0 -66
- package/dist/src/lib/i18n/locales/en/fetcher.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/index.d.ts +0 -344
- package/dist/src/lib/i18n/locales/en/index.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/node.d.ts +0 -41
- package/dist/src/lib/i18n/locales/en/node.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/prompts.d.ts +0 -65
- package/dist/src/lib/i18n/locales/en/prompts.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/resources.d.ts +0 -41
- package/dist/src/lib/i18n/locales/en/resources.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/server.d.ts +0 -30
- package/dist/src/lib/i18n/locales/en/server.js.map +0 -1
- package/dist/src/lib/i18n/locales/en/tools.d.ts +0 -24
- package/dist/src/lib/i18n/locales/en/tools.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/browser.d.ts +0 -61
- package/dist/src/lib/i18n/locales/zh/browser.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/client.d.ts +0 -38
- package/dist/src/lib/i18n/locales/zh/client.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/errors.d.ts +0 -17
- package/dist/src/lib/i18n/locales/zh/errors.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/fetcher.d.ts +0 -66
- package/dist/src/lib/i18n/locales/zh/fetcher.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/index.d.ts +0 -343
- package/dist/src/lib/i18n/locales/zh/index.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/node.d.ts +0 -41
- package/dist/src/lib/i18n/locales/zh/node.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/prompts.d.ts +0 -65
- package/dist/src/lib/i18n/locales/zh/prompts.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/resources.d.ts +0 -41
- package/dist/src/lib/i18n/locales/zh/resources.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/server.d.ts +0 -30
- package/dist/src/lib/i18n/locales/zh/server.js.map +0 -1
- package/dist/src/lib/i18n/locales/zh/tools.d.ts +0 -24
- package/dist/src/lib/i18n/locales/zh/tools.js.map +0 -1
- package/dist/src/lib/i18n/logger.d.ts +0 -38
- package/dist/src/lib/i18n/logger.js.map +0 -1
- package/dist/src/lib/logger.d.ts +0 -32
- package/dist/src/lib/logger.js.map +0 -1
- package/dist/src/lib/server/browser.d.ts +0 -34
- package/dist/src/lib/server/browser.js.map +0 -1
- package/dist/src/lib/server/fetcher.d.ts +0 -20
- package/dist/src/lib/server/fetcher.js.map +0 -1
- package/dist/src/lib/server/index.d.ts +0 -10
- package/dist/src/lib/server/index.js.map +0 -1
- package/dist/src/lib/server/logger.js +0 -23
- package/dist/src/lib/server/prompts.d.ts +0 -11
- package/dist/src/lib/server/prompts.js.map +0 -1
- package/dist/src/lib/server/resources.d.ts +0 -11
- package/dist/src/lib/server/resources.js.map +0 -1
- package/dist/src/lib/server/tools.d.ts +0 -12
- package/dist/src/lib/server/tools.js.map +0 -1
- package/dist/src/lib/server/types.d.ts +0 -71
- package/dist/src/lib/server/types.js.map +0 -1
- package/dist/src/lib/types.d.ts +0 -119
- package/dist/src/lib/types.js.map +0 -1
- package/dist/src/mcp-server.d.ts +0 -6
- package/dist/src/mcp-server.js.map +0 -1
- package/dist/tests/jest.setup.d.ts +0 -6
- package/dist/tests/jest.setup.js +0 -30
- package/dist/tests/jest.setup.js.map +0 -1
- package/dist/tests/test-direct-client.d.ts +0 -6
- package/dist/tests/test-direct-client.js.map +0 -1
- package/dist/tests/test-mcp-methods.d.ts +0 -6
- package/dist/tests/test-mcp-methods.js.map +0 -1
- package/dist/tests/test-mcp.d.ts +0 -6
- package/dist/tests/test-mcp.js.map +0 -1
- package/dist/tests/test-mini4k.d.ts +0 -6
- package/dist/tests/test-mini4k.js.map +0 -1
|
@@ -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 {
|
|
6
|
+
import { BrowserInstance } from '../fetchers/browser/BrowserInstance.js';
|
|
7
7
|
import { log, COMPONENTS } from '../logger.js';
|
|
8
8
|
import { isAccessDeniedError, isNetworkError } from '../utils/errorDetection.js';
|
|
9
9
|
// 全局浏览器实例 (Global browser instance)
|
|
@@ -34,7 +34,7 @@ export async function closeBrowserInstance(debug = false) {
|
|
|
34
34
|
if (debug) {
|
|
35
35
|
log('server.closingBrowser', debug, {}, COMPONENTS.SERVER);
|
|
36
36
|
}
|
|
37
|
-
await
|
|
37
|
+
await BrowserInstance.closeBrowser(debug);
|
|
38
38
|
browserInitialized = false;
|
|
39
39
|
}
|
|
40
40
|
}
|
|
@@ -46,15 +46,47 @@ export async function closeBrowserInstance(debug = false) {
|
|
|
46
46
|
*/
|
|
47
47
|
export function shouldSwitchToBrowser(error) {
|
|
48
48
|
// 检查错误是否表明需要浏览器模式 (Check if error indicates browser mode is needed)
|
|
49
|
-
if (error
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
errorMessage.toLowerCase().includes('fetch failed');
|
|
49
|
+
if (!error)
|
|
50
|
+
return false;
|
|
51
|
+
// 提取错误消息,无论错误对象的形式如何
|
|
52
|
+
let errorMessage;
|
|
53
|
+
if (typeof error === 'string') {
|
|
54
|
+
errorMessage = error;
|
|
56
55
|
}
|
|
57
|
-
|
|
56
|
+
else if (error instanceof Error) {
|
|
57
|
+
errorMessage = error.message;
|
|
58
|
+
}
|
|
59
|
+
else if (error && typeof error === 'object') {
|
|
60
|
+
if ('message' in error && typeof error.message === 'string') {
|
|
61
|
+
errorMessage = error.message;
|
|
62
|
+
}
|
|
63
|
+
else if ('content' in error && Array.isArray(error.content) && error.content.length > 0) {
|
|
64
|
+
// 处理 MCP 响应格式
|
|
65
|
+
const content = error.content[0];
|
|
66
|
+
errorMessage = content && typeof content === 'object' && 'text' in content ? String(content.text) : String(error);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
try {
|
|
70
|
+
errorMessage = JSON.stringify(error);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
errorMessage = String(error);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
errorMessage = String(error);
|
|
79
|
+
}
|
|
80
|
+
// 检查是否包含 HTTP 403 Forbidden 错误,这是最常见的需要切换到浏览器模式的情况
|
|
81
|
+
if (errorMessage.includes('403') ||
|
|
82
|
+
errorMessage.toLowerCase().includes('forbidden')) {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
return isAccessDeniedError(errorMessage) ||
|
|
86
|
+
isNetworkError(errorMessage) ||
|
|
87
|
+
errorMessage.toLowerCase().includes('javascript required') ||
|
|
88
|
+
errorMessage.toLowerCase().includes('und_err_connect_timeout') ||
|
|
89
|
+
errorMessage.toLowerCase().includes('fetch failed');
|
|
58
90
|
}
|
|
59
91
|
/**
|
|
60
92
|
* 检查是否应该使用浏览器模式 (Check if browser mode should be used)
|
|
@@ -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 {
|
|
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,15 @@ 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
|
|
34
|
+
return await Fetcher.html(params);
|
|
36
35
|
case 'json':
|
|
37
|
-
return await
|
|
36
|
+
return await Fetcher.json(params);
|
|
38
37
|
case 'txt':
|
|
39
|
-
return await
|
|
38
|
+
return await Fetcher.txt(params);
|
|
40
39
|
case 'markdown':
|
|
41
|
-
return await
|
|
40
|
+
return await Fetcher.markdown(params);
|
|
41
|
+
default:
|
|
42
|
+
throw new Error(`Unsupported content type: ${type}`);
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
else {
|
|
@@ -48,63 +49,112 @@ export async function fetchWithAutoDetect(params, type) {
|
|
|
48
49
|
}
|
|
49
50
|
try {
|
|
50
51
|
// 根据类型选择合适的标准获取方法 (Choose appropriate standard fetching method based on type)
|
|
52
|
+
let result;
|
|
51
53
|
switch (type) {
|
|
52
54
|
case 'html': {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return {
|
|
56
|
-
content: [{ type: 'text', text: result.html }],
|
|
57
|
-
isError: false
|
|
58
|
-
};
|
|
55
|
+
result = await Fetcher.html(params);
|
|
56
|
+
break;
|
|
59
57
|
}
|
|
60
58
|
case 'json': {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return {
|
|
64
|
-
content: [{ type: 'text', text: typeof result.json === 'string' ? result.json : JSON.stringify(result.json, null, 2) }],
|
|
65
|
-
isError: false
|
|
66
|
-
};
|
|
59
|
+
result = await Fetcher.json(params);
|
|
60
|
+
break;
|
|
67
61
|
}
|
|
68
62
|
case 'txt': {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
content: [{ type: 'text', text: result.text }],
|
|
73
|
-
isError: false
|
|
74
|
-
};
|
|
63
|
+
result = await Fetcher.txt(params);
|
|
64
|
+
break;
|
|
75
65
|
}
|
|
76
66
|
case 'markdown': {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
67
|
+
result = await Fetcher.markdown(params);
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
default:
|
|
71
|
+
throw new Error(`Unsupported content type: ${type}`);
|
|
72
|
+
}
|
|
73
|
+
// 检查结果是否为错误,并且是否包含403或forbidden关键词
|
|
74
|
+
if (result.isError && autoDetectMode) {
|
|
75
|
+
const errorText = result.content && result.content[0] && result.content[0].text
|
|
76
|
+
? String(result.content[0].text)
|
|
77
|
+
: '';
|
|
78
|
+
const is403Error = errorText.includes('403') ||
|
|
79
|
+
errorText.toLowerCase().includes('forbidden');
|
|
80
|
+
if (is403Error || shouldSwitchToBrowser(errorText)) {
|
|
81
|
+
if (debug) {
|
|
82
|
+
log('server.switchingToBrowserMode', debug, {
|
|
83
|
+
url: params.url,
|
|
84
|
+
error: errorText,
|
|
85
|
+
reason: is403Error ? '403 Forbidden' : 'Other error requiring browser'
|
|
86
|
+
}, COMPONENTS.SERVER);
|
|
87
|
+
}
|
|
88
|
+
// 确保浏览器已初始化
|
|
89
|
+
await initializeBrowser(debug);
|
|
90
|
+
// 设置浏览器模式参数
|
|
91
|
+
const browserParams = {
|
|
92
|
+
...params,
|
|
93
|
+
useBrowser: true,
|
|
94
|
+
debug: debug
|
|
82
95
|
};
|
|
96
|
+
// 根据类型选择合适的浏览器获取方法
|
|
97
|
+
let browserResult;
|
|
98
|
+
switch (type) {
|
|
99
|
+
case 'html':
|
|
100
|
+
browserResult = await Fetcher.html(browserParams);
|
|
101
|
+
break;
|
|
102
|
+
case 'json':
|
|
103
|
+
browserResult = await Fetcher.json(browserParams);
|
|
104
|
+
break;
|
|
105
|
+
case 'txt':
|
|
106
|
+
browserResult = await Fetcher.txt(browserParams);
|
|
107
|
+
break;
|
|
108
|
+
case 'markdown':
|
|
109
|
+
browserResult = await Fetcher.markdown(browserParams);
|
|
110
|
+
break;
|
|
111
|
+
default:
|
|
112
|
+
throw new Error(`Unsupported content type: ${type}`);
|
|
113
|
+
}
|
|
114
|
+
return browserResult;
|
|
83
115
|
}
|
|
84
116
|
}
|
|
117
|
+
return result;
|
|
85
118
|
}
|
|
86
119
|
catch (error) {
|
|
87
120
|
// 如果标准模式失败且启用了自动检测
|
|
88
|
-
|
|
121
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
122
|
+
// 检查是否应该切换到浏览器模式
|
|
123
|
+
// 特别处理 HTTP 403 Forbidden 错误,这是最常见的需要切换到浏览器模式的情况
|
|
124
|
+
const shouldSwitch = autoDetectMode && (shouldSwitchToBrowser(error) ||
|
|
125
|
+
errorMessage.includes('403') ||
|
|
126
|
+
errorMessage.toLowerCase().includes('forbidden'));
|
|
127
|
+
if (shouldSwitch) {
|
|
89
128
|
if (debug) {
|
|
90
129
|
log('server.switchingToBrowserMode', debug, { url: params.url }, COMPONENTS.SERVER);
|
|
91
130
|
}
|
|
92
131
|
// 确保浏览器已初始化
|
|
93
132
|
await initializeBrowser(debug);
|
|
94
133
|
// 设置浏览器模式参数
|
|
95
|
-
|
|
96
|
-
|
|
134
|
+
const browserParams = {
|
|
135
|
+
...params,
|
|
136
|
+
useBrowser: true,
|
|
137
|
+
debug: debug
|
|
138
|
+
};
|
|
97
139
|
// 根据类型选择合适的浏览器获取方法
|
|
140
|
+
let browserResult;
|
|
98
141
|
switch (type) {
|
|
99
142
|
case 'html':
|
|
100
|
-
|
|
143
|
+
browserResult = await Fetcher.html(browserParams);
|
|
144
|
+
break;
|
|
101
145
|
case 'json':
|
|
102
|
-
|
|
146
|
+
browserResult = await Fetcher.json(browserParams);
|
|
147
|
+
break;
|
|
103
148
|
case 'txt':
|
|
104
|
-
|
|
149
|
+
browserResult = await Fetcher.txt(browserParams);
|
|
150
|
+
break;
|
|
105
151
|
case 'markdown':
|
|
106
|
-
|
|
152
|
+
browserResult = await Fetcher.markdown(browserParams);
|
|
153
|
+
break;
|
|
154
|
+
default:
|
|
155
|
+
throw new Error(`Unsupported content type: ${type}`);
|
|
107
156
|
}
|
|
157
|
+
return browserResult;
|
|
108
158
|
}
|
|
109
159
|
// 如果不需要切换到浏览器模式,则抛出原始错误
|
|
110
160
|
throw error;
|
|
@@ -127,4 +177,4 @@ export async function fetchWithAutoDetect(params, type) {
|
|
|
127
177
|
content: [{ type: 'text', text: `Unsupported content type: ${type}` }],
|
|
128
178
|
isError: true
|
|
129
179
|
};
|
|
130
|
-
}
|
|
180
|
+
} // 修复注释
|
|
@@ -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
|
|
7
|
-
import { StdioServerTransport } from
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
+
}
|
package/dist/src/mcp-server.js
CHANGED
|
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
|