@lmcc-dev/mult-fetch-mcp-server 1.0.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.
Files changed (50) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +512 -0
  3. package/README.zh.md +510 -0
  4. package/dist/index.js +21 -0
  5. package/dist/src/cli-language.js +78 -0
  6. package/dist/src/client.js +284 -0
  7. package/dist/src/index.js +21 -0
  8. package/dist/src/lib/BrowserFetcher.js +753 -0
  9. package/dist/src/lib/NodeFetcher.js +428 -0
  10. package/dist/src/lib/example.js +93 -0
  11. package/dist/src/lib/i18n/index.js +36 -0
  12. package/dist/src/lib/i18n/locales/en/browser.js +53 -0
  13. package/dist/src/lib/i18n/locales/en/client.js +40 -0
  14. package/dist/src/lib/i18n/locales/en/errors.js +18 -0
  15. package/dist/src/lib/i18n/locales/en/fetcher.js +67 -0
  16. package/dist/src/lib/i18n/locales/en/index.js +26 -0
  17. package/dist/src/lib/i18n/locales/en/node.js +42 -0
  18. package/dist/src/lib/i18n/locales/en/prompts.js +72 -0
  19. package/dist/src/lib/i18n/locales/en/resources.js +47 -0
  20. package/dist/src/lib/i18n/locales/en/server.js +32 -0
  21. package/dist/src/lib/i18n/locales/en/tools.js +25 -0
  22. package/dist/src/lib/i18n/locales/zh/browser.js +53 -0
  23. package/dist/src/lib/i18n/locales/zh/client.js +39 -0
  24. package/dist/src/lib/i18n/locales/zh/errors.js +18 -0
  25. package/dist/src/lib/i18n/locales/zh/fetcher.js +67 -0
  26. package/dist/src/lib/i18n/locales/zh/index.js +26 -0
  27. package/dist/src/lib/i18n/locales/zh/node.js +42 -0
  28. package/dist/src/lib/i18n/locales/zh/prompts.js +72 -0
  29. package/dist/src/lib/i18n/locales/zh/resources.js +47 -0
  30. package/dist/src/lib/i18n/locales/zh/server.js +32 -0
  31. package/dist/src/lib/i18n/locales/zh/tools.js +25 -0
  32. package/dist/src/lib/i18n/logger.js +57 -0
  33. package/dist/src/lib/logger.js +126 -0
  34. package/dist/src/lib/server/browser.js +86 -0
  35. package/dist/src/lib/server/fetcher.js +130 -0
  36. package/dist/src/lib/server/index.js +73 -0
  37. package/dist/src/lib/server/logger.js +23 -0
  38. package/dist/src/lib/server/prompts.js +207 -0
  39. package/dist/src/lib/server/resources.js +171 -0
  40. package/dist/src/lib/server/tools.js +346 -0
  41. package/dist/src/lib/server/types.js +6 -0
  42. package/dist/src/lib/types.js +35 -0
  43. package/dist/src/mcp-server.js +22 -0
  44. package/dist/tests/test-direct-client.js +129 -0
  45. package/dist/tests/test-mcp-methods.js +114 -0
  46. package/dist/tests/test-mcp.js +145 -0
  47. package/dist/tests/test-mini4k.js +147 -0
  48. package/images/example_en.png +0 -0
  49. package/images/example_zh.png +0 -0
  50. package/package.json +80 -0
@@ -0,0 +1,145 @@
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 { spawn } from 'child_process';
7
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
8
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
9
+ import path from 'path';
10
+ import { fileURLToPath } from 'url';
11
+ import fs from 'fs';
12
+ // 获取当前文件的目录路径 (Get the directory path of the current file)
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+ // 获取项目根目录 (Get the project root directory)
16
+ const rootDir = process.cwd();
17
+ /**
18
+ * 测试 MCP 客户端与服务器的交互 (Test interaction between MCP client and server)
19
+ * 启动服务器进程并使用客户端发送请求 (Start server process and send requests using client)
20
+ */
21
+ async function testMCP() {
22
+ console.log('开始测试 MCP 客户端与服务器的交互...');
23
+ let serverProcess = null;
24
+ let client = null;
25
+ try {
26
+ // 启动 MCP 服务器 (Start MCP server)
27
+ const serverPath = path.resolve(rootDir, 'dist/index.js');
28
+ // 检查文件是否存在
29
+ if (!fs.existsSync(serverPath)) {
30
+ console.error(`错误:服务器文件不存在: ${serverPath}`);
31
+ console.log('当前目录结构:');
32
+ console.log('rootDir:', rootDir);
33
+ console.log('dist目录内容:', fs.readdirSync(path.resolve(rootDir, 'dist')));
34
+ process.exit(1);
35
+ }
36
+ console.log(`启动 MCP 服务器: ${serverPath}`);
37
+ // 启动服务器进程
38
+ serverProcess = spawn('node', [serverPath], {
39
+ stdio: ['pipe', 'pipe', 'inherit']
40
+ });
41
+ // 创建客户端传输层
42
+ const transport = new StdioClientTransport({
43
+ command: 'node',
44
+ args: [serverPath],
45
+ stderr: 'inherit',
46
+ env: {
47
+ ...process.env, // 传递所有环境变量,包括MCP_LANG
48
+ }
49
+ });
50
+ // 创建客户端
51
+ client = new Client({
52
+ name: "test-mcp-client",
53
+ version: "1.0.0"
54
+ });
55
+ // 连接到传输层
56
+ await client.connect(transport);
57
+ // 等待服务器启动
58
+ await new Promise(resolve => setTimeout(resolve, 1000));
59
+ try {
60
+ // 测试 listTools 方法
61
+ console.log('测试 listTools 方法...');
62
+ const tools = await client.listTools();
63
+ console.log('可用工具列表:');
64
+ console.log(tools);
65
+ console.log('');
66
+ // 测试 fetch_html 方法
67
+ console.log('测试 fetch_html 方法...');
68
+ const htmlResult = await client.callTool({
69
+ name: 'fetch_html',
70
+ arguments: {
71
+ url: 'https://example.com',
72
+ debug: true
73
+ }
74
+ });
75
+ if (htmlResult.isError) {
76
+ console.error('获取 HTML 失败:', htmlResult.content[0].text);
77
+ }
78
+ else {
79
+ console.log(`获取 HTML 成功,内容长度: ${htmlResult.content[0].text.length} 字节`);
80
+ console.log(`HTML 内容预览: ${htmlResult.content[0].text.substring(0, 100)}...`);
81
+ }
82
+ console.log('');
83
+ // 测试 fetch_json 方法
84
+ console.log('测试 fetch_json 方法...');
85
+ const jsonResult = await client.callTool({
86
+ name: 'fetch_json',
87
+ arguments: {
88
+ url: 'https://jsonplaceholder.typicode.com/todos/1',
89
+ debug: true
90
+ }
91
+ });
92
+ if (jsonResult.isError) {
93
+ console.error('获取 JSON 失败:', jsonResult.content[0].text);
94
+ }
95
+ else {
96
+ console.log(`获取 JSON 成功,内容: ${jsonResult.content[0].text}`);
97
+ }
98
+ // 关闭浏览器实例(如果有的话)
99
+ console.log('\n关闭浏览器实例...');
100
+ await client.callTool({
101
+ name: 'fetch_html',
102
+ arguments: {
103
+ url: 'about:blank',
104
+ debug: true,
105
+ useBrowser: true,
106
+ closeBrowser: true
107
+ }
108
+ });
109
+ console.log('\n所有测试完成!');
110
+ }
111
+ catch (error) {
112
+ console.error('测试过程中出错:', error);
113
+ }
114
+ }
115
+ finally {
116
+ // 确保关闭客户端连接
117
+ if (client) {
118
+ try {
119
+ await client.close();
120
+ console.log('客户端连接已关闭');
121
+ }
122
+ catch (err) {
123
+ console.error('关闭客户端连接时出错:', err);
124
+ }
125
+ }
126
+ // 确保关闭服务器进程
127
+ if (serverProcess) {
128
+ try {
129
+ serverProcess.kill('SIGTERM');
130
+ console.log('服务器进程已终止');
131
+ }
132
+ catch (err) {
133
+ console.error('终止服务器进程时出错:', err);
134
+ }
135
+ }
136
+ // 强制退出进程
137
+ console.log('测试完成,强制退出进程');
138
+ process.exit(0);
139
+ }
140
+ }
141
+ // 运行测试
142
+ testMCP().catch(error => {
143
+ console.error('测试失败:', error);
144
+ process.exit(1);
145
+ });
@@ -0,0 +1,147 @@
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 { spawn } from 'child_process';
7
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
8
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
9
+ import path from 'path';
10
+ import { fileURLToPath } from 'url';
11
+ import fs from 'fs';
12
+ // 获取当前文件的目录路径 (Get the directory path of the current file)
13
+ const __filename = fileURLToPath(import.meta.url);
14
+ const __dirname = path.dirname(__filename);
15
+ // 获取项目根目录 (Get the project root directory)
16
+ const rootDir = process.cwd();
17
+ /**
18
+ * 测试 mini4k.com 网站(已知需要浏览器模式) (Test mini4k.com website (known to require browser mode))
19
+ * 验证浏览器模式下的网页获取功能 (Verify webpage fetching functionality in browser mode)
20
+ */
21
+ async function testMini4k() {
22
+ console.log('开始测试 mini4k.com 网站...');
23
+ let serverProcess = null;
24
+ let client = null;
25
+ try {
26
+ // 启动服务器进程
27
+ const serverPath = path.resolve(rootDir, 'dist/index.js');
28
+ console.log(`启动服务器: ${serverPath}`);
29
+ serverProcess = spawn('node', [serverPath], {
30
+ stdio: ['pipe', 'pipe', 'inherit']
31
+ });
32
+ // 检查文件是否存在
33
+ if (!fs.existsSync(serverPath)) {
34
+ console.error(`错误:服务器文件不存在: ${serverPath}`);
35
+ console.log('当前目录结构:');
36
+ console.log('rootDir:', rootDir);
37
+ console.log('dist目录内容:', fs.readdirSync(path.resolve(rootDir, 'dist')));
38
+ process.exit(1);
39
+ }
40
+ // 创建客户端传输层
41
+ const transport = new StdioClientTransport({
42
+ command: 'node',
43
+ args: [serverPath],
44
+ stderr: 'inherit',
45
+ env: {
46
+ ...process.env, // 传递所有环境变量,包括MCP_LANG
47
+ }
48
+ });
49
+ // 创建客户端
50
+ client = new Client({
51
+ name: "test-mini4k-client",
52
+ version: "1.0.0"
53
+ });
54
+ // 连接到传输层
55
+ await client.connect(transport);
56
+ // 等待服务器启动
57
+ await new Promise(resolve => setTimeout(resolve, 1000));
58
+ try {
59
+ console.log('\n测试标准模式获取 mini4k.com...');
60
+ // 使用标准模式获取
61
+ const standardResult = await client.callTool({
62
+ name: 'fetch_html',
63
+ arguments: {
64
+ url: 'https://mini4k.com',
65
+ debug: true,
66
+ timeout: 30000,
67
+ waitForTimeout: 3000,
68
+ scrollToBottom: false // 禁用滚动到底部
69
+ }
70
+ });
71
+ console.log(`标准模式结果 - 是否错误: ${standardResult.isError}`);
72
+ if (!standardResult.isError && standardResult.content && standardResult.content[0]) {
73
+ console.log(`标准模式内容长度: ${standardResult.content[0].text.length} 字节`);
74
+ console.log(`标准模式内容预览: ${standardResult.content[0].text.substring(0, 200)}...`);
75
+ }
76
+ else if (standardResult.isError) {
77
+ console.log(`标准模式错误: ${standardResult.content[0].text}`);
78
+ }
79
+ console.log('\n测试浏览器模式获取 mini4k.com...');
80
+ // 使用浏览器模式获取
81
+ const browserResult = await client.callTool({
82
+ name: 'fetch_html',
83
+ arguments: {
84
+ url: 'https://mini4k.com',
85
+ debug: true,
86
+ useBrowser: true,
87
+ timeout: 30000,
88
+ waitForTimeout: 3000,
89
+ scrollToBottom: false // 禁用滚动到底部
90
+ }
91
+ });
92
+ console.log(`浏览器模式结果 - 是否错误: ${browserResult.isError}`);
93
+ if (!browserResult.isError && browserResult.content && browserResult.content[0]) {
94
+ console.log(`浏览器模式内容长度: ${browserResult.content[0].text.length} 字节`);
95
+ console.log(`浏览器模式内容预览: ${browserResult.content[0].text.substring(0, 200)}...`);
96
+ }
97
+ else if (browserResult.isError) {
98
+ console.log(`浏览器模式错误: ${browserResult.content[0].text}`);
99
+ }
100
+ // 关闭浏览器实例
101
+ console.log('\n关闭浏览器实例...');
102
+ await client.callTool({
103
+ name: 'fetch_html',
104
+ arguments: {
105
+ url: 'about:blank',
106
+ debug: true,
107
+ useBrowser: true,
108
+ closeBrowser: true
109
+ }
110
+ });
111
+ console.log('\n所有测试完成!');
112
+ }
113
+ catch (error) {
114
+ console.error('测试过程中出错:', error);
115
+ }
116
+ }
117
+ finally {
118
+ // 确保关闭客户端连接
119
+ if (client) {
120
+ try {
121
+ await client.close();
122
+ console.log('客户端连接已关闭');
123
+ }
124
+ catch (err) {
125
+ console.error('关闭客户端连接时出错:', err);
126
+ }
127
+ }
128
+ // 确保关闭服务器进程
129
+ if (serverProcess) {
130
+ try {
131
+ serverProcess.kill('SIGTERM');
132
+ console.log('服务器进程已终止');
133
+ }
134
+ catch (err) {
135
+ console.error('终止服务器进程时出错:', err);
136
+ }
137
+ }
138
+ // 强制退出进程
139
+ console.log('测试完成,强制退出进程');
140
+ process.exit(0);
141
+ }
142
+ }
143
+ // 运行测试
144
+ testMini4k().catch(error => {
145
+ console.error('测试失败:', error);
146
+ process.exit(1);
147
+ });
Binary file
Binary file
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@lmcc-dev/mult-fetch-mcp-server",
3
+ "version": "1.0.1",
4
+ "description": "An MCP protocol-based web content fetching tool that supports multiple modes and formats, can be integrated with AI assistants like Claude",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "mult-fetch-mcp-server": "./dist/index.js"
9
+ },
10
+ "license": "MIT",
11
+ "author": "Martin (@lmcc.dev)",
12
+ "homepage": "https://github.com/lmcc-dev/mult-fetch-mcp-server",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/lmcc-dev/mult-fetch-mcp-server.git"
16
+ },
17
+ "bugs": {
18
+ "url": "https://github.com/lmcc-dev/mult-fetch-mcp-server/issues"
19
+ },
20
+ "engines": {
21
+ "node": ">=18.0.0"
22
+ },
23
+ "scripts": {
24
+ "build": "tsc && shx chmod +x dist/src/*.js dist/tests/*.js || true && shx chmod +x dist/*.js || true",
25
+ "prepare": "npm run build",
26
+ "dev": "tsc --watch",
27
+ "start": "node dist/index.js",
28
+ "test:mcp": "node dist/tests/test-mcp.js",
29
+ "test:mini4k": "node dist/tests/test-mini4k.js",
30
+ "test:direct": "node dist/tests/test-direct-client.js",
31
+ "client": "node dist/src/client.js",
32
+ "server": "node dist/index.js",
33
+ "prepublishOnly": "npm run build",
34
+ "publish": "npm publish --access public"
35
+ },
36
+ "keywords": [
37
+ "mcp",
38
+ "model-context-protocol",
39
+ "claude",
40
+ "ai",
41
+ "web-scraping",
42
+ "fetch",
43
+ "browser",
44
+ "puppeteer",
45
+ "html",
46
+ "json",
47
+ "markdown",
48
+ "text",
49
+ "proxy"
50
+ ],
51
+ "dependencies": {
52
+ "@modelcontextprotocol/sdk": "^1.6.1",
53
+ "http-proxy-agent": "^7.0.2",
54
+ "https-proxy-agent": "^7.0.6",
55
+ "i18next": "^24.2.2",
56
+ "jsdom": "^25.0.1",
57
+ "node-fetch": "^2.7.0",
58
+ "puppeteer": "^24.4.0",
59
+ "puppeteer-extra": "^3.3.6",
60
+ "puppeteer-extra-plugin-stealth": "^2.11.2",
61
+ "turndown": "^7.2.0",
62
+ "zod": "^3.24.2"
63
+ },
64
+ "devDependencies": {
65
+ "@types/jsdom": "^21.1.7",
66
+ "@types/node": "^22.10.2",
67
+ "@types/node-fetch": "^2.6.12",
68
+ "@types/puppeteer": "^5.4.7",
69
+ "@types/turndown": "^5.0.5",
70
+ "shx": "^0.3.4",
71
+ "typescript": "^5.7.2"
72
+ },
73
+ "files": [
74
+ "dist",
75
+ "README.md",
76
+ "README.zh.md",
77
+ "LICENSE",
78
+ "images"
79
+ ]
80
+ }