@coofly/agent-browser-mcp 1.0.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 (69) hide show
  1. package/.dockerignore +7 -0
  2. package/CLAUDE.md +82 -0
  3. package/Dockerfile +41 -0
  4. package/LICENSE +674 -0
  5. package/README.md +191 -0
  6. package/README_ZH.md +191 -0
  7. package/config.example.yaml +44 -0
  8. package/dist/config.d.ts +43 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +21 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/index.d.ts +3 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +15 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/server.d.ts +43 -0
  17. package/dist/server.d.ts.map +1 -0
  18. package/dist/server.js +334 -0
  19. package/dist/server.js.map +1 -0
  20. package/dist/test-cli.d.ts +2 -0
  21. package/dist/test-cli.d.ts.map +1 -0
  22. package/dist/test-cli.js +22 -0
  23. package/dist/test-cli.js.map +1 -0
  24. package/dist/test.d.ts +2 -0
  25. package/dist/test.d.ts.map +1 -0
  26. package/dist/test.js +17 -0
  27. package/dist/test.js.map +1 -0
  28. package/dist/tools/advanced.d.ts +19 -0
  29. package/dist/tools/advanced.d.ts.map +1 -0
  30. package/dist/tools/advanced.js +40 -0
  31. package/dist/tools/advanced.js.map +1 -0
  32. package/dist/tools/information.d.ts +23 -0
  33. package/dist/tools/information.d.ts.map +1 -0
  34. package/dist/tools/information.js +41 -0
  35. package/dist/tools/information.js.map +1 -0
  36. package/dist/tools/interaction.d.ts +27 -0
  37. package/dist/tools/interaction.d.ts.map +1 -0
  38. package/dist/tools/interaction.js +49 -0
  39. package/dist/tools/interaction.js.map +1 -0
  40. package/dist/tools/navigation.d.ts +21 -0
  41. package/dist/tools/navigation.d.ts.map +1 -0
  42. package/dist/tools/navigation.js +37 -0
  43. package/dist/tools/navigation.js.map +1 -0
  44. package/dist/tools/storage.d.ts +16 -0
  45. package/dist/tools/storage.d.ts.map +1 -0
  46. package/dist/tools/storage.js +28 -0
  47. package/dist/tools/storage.js.map +1 -0
  48. package/dist/utils/configLoader.d.ts +19 -0
  49. package/dist/utils/configLoader.d.ts.map +1 -0
  50. package/dist/utils/configLoader.js +163 -0
  51. package/dist/utils/configLoader.js.map +1 -0
  52. package/dist/utils/executor.d.ts +26 -0
  53. package/dist/utils/executor.d.ts.map +1 -0
  54. package/dist/utils/executor.js +71 -0
  55. package/dist/utils/executor.js.map +1 -0
  56. package/package.json +35 -0
  57. package/src/config.ts +60 -0
  58. package/src/index.ts +16 -0
  59. package/src/server.ts +388 -0
  60. package/src/test-cli.ts +27 -0
  61. package/src/test.ts +20 -0
  62. package/src/tools/advanced.ts +55 -0
  63. package/src/tools/information.ts +54 -0
  64. package/src/tools/interaction.ts +74 -0
  65. package/src/tools/navigation.ts +51 -0
  66. package/src/tools/storage.ts +36 -0
  67. package/src/utils/configLoader.ts +195 -0
  68. package/src/utils/executor.ts +100 -0
  69. package/tsconfig.json +18 -0
@@ -0,0 +1,36 @@
1
+ import { executeCommand, ExecuteOptions } from '../utils/executor.js';
2
+
3
+ /**
4
+ * 存储相关工具
5
+ */
6
+
7
+ /** 获取所有 Cookie */
8
+ export async function getCookies(options?: ExecuteOptions) {
9
+ return executeCommand(['cookie', 'list'], options);
10
+ }
11
+
12
+ /** 设置 Cookie */
13
+ export async function setCookie(
14
+ name: string,
15
+ value: string,
16
+ options?: ExecuteOptions & { domain?: string; path?: string }
17
+ ) {
18
+ const args = ['cookie', 'set', name, value];
19
+ if (options?.domain) {
20
+ args.push('--domain', options.domain);
21
+ }
22
+ if (options?.path) {
23
+ args.push('--path', options.path);
24
+ }
25
+ return executeCommand(args, options);
26
+ }
27
+
28
+ /** 删除 Cookie */
29
+ export async function deleteCookie(name: string, options?: ExecuteOptions) {
30
+ return executeCommand(['cookie', 'delete', name], options);
31
+ }
32
+
33
+ /** 清除所有 Cookie */
34
+ export async function clearCookies(options?: ExecuteOptions) {
35
+ return executeCommand(['cookie', 'clear'], options);
36
+ }
@@ -0,0 +1,195 @@
1
+ /**
2
+ * 配置加载器
3
+ * 支持从文件、环境变量、命令行参数加载配置
4
+ */
5
+
6
+ import { readFileSync, existsSync } from 'fs';
7
+ import { resolve } from 'path';
8
+ import { parse as parseYaml } from 'yaml';
9
+ import { AppConfig, defaultConfig } from '../config.js';
10
+
11
+ /**
12
+ * 命令行参数解析结果
13
+ */
14
+ interface CliArgs {
15
+ sse?: boolean;
16
+ port?: number;
17
+ host?: string;
18
+ cdp?: string;
19
+ config?: string;
20
+ }
21
+
22
+ /**
23
+ * 解析命令行参数
24
+ */
25
+ function parseCliArgs(): CliArgs {
26
+ const args = process.argv.slice(2);
27
+ const result: CliArgs = {};
28
+
29
+ for (let i = 0; i < args.length; i++) {
30
+ const arg = args[i];
31
+
32
+ if (arg === '--sse') {
33
+ result.sse = true;
34
+ } else if (arg === '--port' && args[i + 1]) {
35
+ result.port = parseInt(args[++i], 10);
36
+ } else if (arg === '--host' && args[i + 1]) {
37
+ result.host = args[++i];
38
+ } else if (arg === '--cdp' && args[i + 1]) {
39
+ result.cdp = args[++i];
40
+ } else if (arg === '--config' && args[i + 1]) {
41
+ result.config = args[++i];
42
+ }
43
+ }
44
+
45
+ return result;
46
+ }
47
+
48
+ /**
49
+ * 从文件加载配置(仅支持 YAML 格式)
50
+ */
51
+ function loadConfigFile(configPath?: string): Partial<AppConfig> {
52
+ const paths = configPath
53
+ ? [configPath]
54
+ : [
55
+ resolve(process.cwd(), 'config.yaml'),
56
+ resolve(process.cwd(), 'config.yml'),
57
+ ];
58
+
59
+ for (const path of paths) {
60
+ if (existsSync(path)) {
61
+ try {
62
+ const content = readFileSync(path, 'utf-8');
63
+ console.error(`[配置] 从文件加载: ${path}`);
64
+ return parseYaml(content) as Partial<AppConfig>;
65
+ } catch (err) {
66
+ console.error(`[配置] 解析配置文件失败: ${path}`, err);
67
+ }
68
+ }
69
+ }
70
+
71
+ return {};
72
+ }
73
+
74
+ /**
75
+ * 从环境变量加载配置
76
+ */
77
+ function loadEnvConfig(): Partial<AppConfig> {
78
+ const config: Partial<AppConfig> = {};
79
+
80
+ // CDP 配置
81
+ if (process.env.CDP_ENDPOINT) {
82
+ config.cdp = {
83
+ enabled: true,
84
+ endpoint: process.env.CDP_ENDPOINT,
85
+ };
86
+ }
87
+
88
+ // 服务器配置
89
+ if (process.env.MCP_TRANSPORT === 'sse' || process.env.MCP_TRANSPORT === 'stdio') {
90
+ config.server = {
91
+ ...defaultConfig.server,
92
+ transport: process.env.MCP_TRANSPORT,
93
+ };
94
+ }
95
+
96
+ if (process.env.MCP_PORT) {
97
+ config.server = {
98
+ ...defaultConfig.server,
99
+ ...config.server,
100
+ port: parseInt(process.env.MCP_PORT, 10),
101
+ };
102
+ }
103
+
104
+ if (process.env.MCP_HOST) {
105
+ config.server = {
106
+ ...defaultConfig.server,
107
+ ...config.server,
108
+ host: process.env.MCP_HOST,
109
+ };
110
+ }
111
+
112
+ // 浏览器配置
113
+ if (process.env.BROWSER_TIMEOUT) {
114
+ config.browser = {
115
+ timeout: parseInt(process.env.BROWSER_TIMEOUT, 10),
116
+ };
117
+ }
118
+
119
+ return config;
120
+ }
121
+
122
+ /**
123
+ * 深度合并配置对象
124
+ */
125
+ function deepMerge(target: AppConfig, source: Partial<AppConfig>): AppConfig {
126
+ const result = { ...target };
127
+
128
+ if (source.cdp) {
129
+ result.cdp = { ...result.cdp, ...source.cdp };
130
+ }
131
+ if (source.server) {
132
+ result.server = { ...result.server, ...source.server };
133
+ }
134
+ if (source.browser) {
135
+ result.browser = { ...result.browser, ...source.browser };
136
+ }
137
+
138
+ return result;
139
+ }
140
+
141
+ /**
142
+ * 加载完整配置
143
+ * 优先级: 命令行参数 > 环境变量 > 配置文件 > 默认值
144
+ */
145
+ export function loadConfig(): AppConfig {
146
+ const cliArgs = parseCliArgs();
147
+
148
+ // 1. 从默认配置开始
149
+ let config: AppConfig = { ...defaultConfig };
150
+
151
+ // 2. 合并配置文件
152
+ const fileConfig = loadConfigFile(cliArgs.config);
153
+ config = deepMerge(config, fileConfig);
154
+
155
+ // 3. 合并环境变量
156
+ const envConfig = loadEnvConfig();
157
+ config = deepMerge(config, envConfig);
158
+
159
+ // 4. 合并命令行参数(最高优先级)
160
+ if (cliArgs.sse) {
161
+ config.server.transport = 'sse';
162
+ }
163
+ if (cliArgs.port !== undefined) {
164
+ config.server.port = cliArgs.port;
165
+ }
166
+ if (cliArgs.host) {
167
+ config.server.host = cliArgs.host;
168
+ }
169
+ if (cliArgs.cdp) {
170
+ config.cdp.enabled = true;
171
+ config.cdp.endpoint = cliArgs.cdp;
172
+ }
173
+
174
+ return config;
175
+ }
176
+
177
+ /** 全局配置实例 */
178
+ let globalConfig: AppConfig | null = null;
179
+
180
+ /**
181
+ * 获取全局配置(单例)
182
+ */
183
+ export function getConfig(): AppConfig {
184
+ if (!globalConfig) {
185
+ globalConfig = loadConfig();
186
+ }
187
+ return globalConfig;
188
+ }
189
+
190
+ /**
191
+ * 重置配置(用于测试)
192
+ */
193
+ export function resetConfig(): void {
194
+ globalConfig = null;
195
+ }
@@ -0,0 +1,100 @@
1
+ import { spawn } from 'child_process';
2
+
3
+ /**
4
+ * 执行 agent-browser CLI 命令
5
+ */
6
+ export interface ExecuteOptions {
7
+ session?: string;
8
+ profile?: string;
9
+ json?: boolean;
10
+ headed?: boolean;
11
+ timeout?: number;
12
+ /** CDP 远程端点地址 */
13
+ cdp?: string;
14
+ }
15
+
16
+ export interface ExecuteResult {
17
+ success: boolean;
18
+ output: string;
19
+ error?: string;
20
+ }
21
+
22
+ /**
23
+ * 执行 agent-browser 命令
24
+ */
25
+ export async function executeCommand(
26
+ args: string[],
27
+ options: ExecuteOptions = {}
28
+ ): Promise<ExecuteResult> {
29
+ const cmdArgs: string[] = [];
30
+
31
+ // 添加全局选项
32
+ if (options.cdp) {
33
+ cmdArgs.push('--cdp', options.cdp);
34
+ }
35
+ if (options.session) {
36
+ cmdArgs.push('--session', options.session);
37
+ }
38
+ if (options.profile) {
39
+ cmdArgs.push('--profile', options.profile);
40
+ }
41
+ if (options.json !== false) {
42
+ cmdArgs.push('--json');
43
+ }
44
+ if (options.headed) {
45
+ cmdArgs.push('--headed');
46
+ }
47
+
48
+ // 添加命令参数
49
+ cmdArgs.push(...args);
50
+
51
+ return new Promise((resolve) => {
52
+ const timeout = options.timeout || 30000;
53
+ let stdout = '';
54
+ let stderr = '';
55
+
56
+ const proc = spawn('agent-browser', cmdArgs, {
57
+ shell: true,
58
+ timeout,
59
+ });
60
+
61
+ proc.stdout.on('data', (data) => {
62
+ stdout += data.toString();
63
+ });
64
+
65
+ proc.stderr.on('data', (data) => {
66
+ stderr += data.toString();
67
+ });
68
+
69
+ proc.on('close', (code) => {
70
+ if (code === 0) {
71
+ resolve({ success: true, output: stdout.trim() });
72
+ } else {
73
+ resolve({
74
+ success: false,
75
+ output: stdout.trim(),
76
+ error: stderr.trim() || `命令退出码: ${code}`,
77
+ });
78
+ }
79
+ });
80
+
81
+ proc.on('error', (err) => {
82
+ resolve({
83
+ success: false,
84
+ output: '',
85
+ error: `执行错误: ${err.message}`,
86
+ });
87
+ });
88
+ });
89
+ }
90
+
91
+ /**
92
+ * 解析 JSON 输出
93
+ */
94
+ export function parseJsonOutput<T>(output: string): T | null {
95
+ try {
96
+ return JSON.parse(output) as T;
97
+ } catch {
98
+ return null;
99
+ }
100
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "sourceMap": true
15
+ },
16
+ "include": ["src/**/*"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }