@roxybrowser/openapi 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.
- package/README.md +374 -0
- package/lib/browser/browser-creator.d.ts +58 -0
- package/lib/browser/browser-creator.d.ts.map +1 -0
- package/lib/browser/browser-creator.js +286 -0
- package/lib/browser/browser-creator.js.map +1 -0
- package/lib/browser/template-manager.d.ts +48 -0
- package/lib/browser/template-manager.d.ts.map +1 -0
- package/lib/browser/template-manager.js +324 -0
- package/lib/browser/template-manager.js.map +1 -0
- package/lib/index.d.ts +9 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +821 -0
- package/lib/index.js.map +1 -0
- package/lib/proxy/proxy-manager.d.ts +67 -0
- package/lib/proxy/proxy-manager.d.ts.map +1 -0
- package/lib/proxy/proxy-manager.js +278 -0
- package/lib/proxy/proxy-manager.js.map +1 -0
- package/lib/proxy/proxy-validator.d.ts +66 -0
- package/lib/proxy/proxy-validator.d.ts.map +1 -0
- package/lib/proxy/proxy-validator.js +273 -0
- package/lib/proxy/proxy-validator.js.map +1 -0
- package/lib/roxy-client.d.ts +83 -0
- package/lib/roxy-client.d.ts.map +1 -0
- package/lib/roxy-client.js +306 -0
- package/lib/roxy-client.js.map +1 -0
- package/lib/types.d.ts +371 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +36 -0
- package/lib/types.js.map +1 -0
- package/package.json +46 -0
package/lib/index.js
ADDED
|
@@ -0,0 +1,821 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* RoxyBrowser MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Model Context Protocol server for RoxyBrowser automation
|
|
6
|
+
* Provides tools to manage browser instances and get CDP endpoints
|
|
7
|
+
*/
|
|
8
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
9
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
11
|
+
import { RoxyClient } from './roxy-client.js';
|
|
12
|
+
import { BrowserCreator } from './browser/browser-creator.js';
|
|
13
|
+
import { TemplateManager } from './browser/template-manager.js';
|
|
14
|
+
import { ProxyManager } from './proxy/proxy-manager.js';
|
|
15
|
+
import { ConfigError, BrowserCreationError, } from './types.js';
|
|
16
|
+
// ========== Configuration ==========
|
|
17
|
+
function getConfig() {
|
|
18
|
+
const apiHost = process.env.ROXY_API_HOST || 'http://127.0.0.1:50000';
|
|
19
|
+
const apiKey = process.env.ROXY_API_KEY || '';
|
|
20
|
+
const timeout = process.env.ROXY_TIMEOUT ? parseInt(process.env.ROXY_TIMEOUT) : 30000;
|
|
21
|
+
if (!apiKey) {
|
|
22
|
+
throw new ConfigError('ROXY_API_KEY environment variable is required. ' +
|
|
23
|
+
'Get your API key from RoxyBrowser: API -> API配置 -> API Key');
|
|
24
|
+
}
|
|
25
|
+
return { apiHost, apiKey, timeout };
|
|
26
|
+
}
|
|
27
|
+
// ========== Tool Definitions ==========
|
|
28
|
+
const TOOLS = [
|
|
29
|
+
{
|
|
30
|
+
name: 'roxy_list_workspaces',
|
|
31
|
+
description: 'Get list of all workspaces and their projects from RoxyBrowser',
|
|
32
|
+
inputSchema: {
|
|
33
|
+
type: 'object',
|
|
34
|
+
properties: {
|
|
35
|
+
pageIndex: {
|
|
36
|
+
type: 'number',
|
|
37
|
+
description: 'Page index for pagination (default: 1)',
|
|
38
|
+
default: 1,
|
|
39
|
+
},
|
|
40
|
+
pageSize: {
|
|
41
|
+
type: 'number',
|
|
42
|
+
description: 'Number of items per page (default: 15)',
|
|
43
|
+
default: 15,
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'roxy_list_browsers',
|
|
50
|
+
description: 'Get list of browsers in specified workspace/project',
|
|
51
|
+
inputSchema: {
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties: {
|
|
54
|
+
workspaceId: {
|
|
55
|
+
type: 'number',
|
|
56
|
+
description: 'Workspace ID (required)',
|
|
57
|
+
},
|
|
58
|
+
projectIds: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
description: 'Comma-separated project IDs (optional)',
|
|
61
|
+
},
|
|
62
|
+
windowName: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'Filter by browser window name (optional)',
|
|
65
|
+
},
|
|
66
|
+
pageIndex: {
|
|
67
|
+
type: 'number',
|
|
68
|
+
description: 'Page index for pagination (default: 1)',
|
|
69
|
+
default: 1,
|
|
70
|
+
},
|
|
71
|
+
pageSize: {
|
|
72
|
+
type: 'number',
|
|
73
|
+
description: 'Number of items per page (default: 15)',
|
|
74
|
+
default: 15,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
required: ['workspaceId'],
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
name: 'roxy_open_browsers',
|
|
82
|
+
description: 'Open multiple browsers and return their CDP WebSocket endpoints for automation',
|
|
83
|
+
inputSchema: {
|
|
84
|
+
type: 'object',
|
|
85
|
+
properties: {
|
|
86
|
+
workspaceId: {
|
|
87
|
+
type: 'number',
|
|
88
|
+
description: 'Workspace ID (required)',
|
|
89
|
+
},
|
|
90
|
+
dirIds: {
|
|
91
|
+
type: 'array',
|
|
92
|
+
items: { type: 'string' },
|
|
93
|
+
description: 'Array of browser directory IDs to open (required)',
|
|
94
|
+
},
|
|
95
|
+
args: {
|
|
96
|
+
type: 'array',
|
|
97
|
+
items: { type: 'string' },
|
|
98
|
+
description: 'Optional browser startup arguments',
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
required: ['workspaceId', 'dirIds'],
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'roxy_close_browsers',
|
|
106
|
+
description: 'Close multiple browsers by their directory IDs',
|
|
107
|
+
inputSchema: {
|
|
108
|
+
type: 'object',
|
|
109
|
+
properties: {
|
|
110
|
+
dirIds: {
|
|
111
|
+
type: 'array',
|
|
112
|
+
items: { type: 'string' },
|
|
113
|
+
description: 'Array of browser directory IDs to close (required)',
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
required: ['dirIds'],
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: 'roxy_create_browser_simple',
|
|
121
|
+
description: 'Create a browser with simple configuration - ideal for quick setup with basic proxy',
|
|
122
|
+
inputSchema: {
|
|
123
|
+
type: 'object',
|
|
124
|
+
properties: {
|
|
125
|
+
workspaceId: {
|
|
126
|
+
type: 'number',
|
|
127
|
+
description: 'Workspace ID (required)',
|
|
128
|
+
},
|
|
129
|
+
windowName: {
|
|
130
|
+
type: 'string',
|
|
131
|
+
description: 'Browser window name (optional)',
|
|
132
|
+
},
|
|
133
|
+
projectId: {
|
|
134
|
+
type: 'number',
|
|
135
|
+
description: 'Project ID (optional)',
|
|
136
|
+
},
|
|
137
|
+
windowRemark: {
|
|
138
|
+
type: 'string',
|
|
139
|
+
description: 'Window remarks/notes (optional)',
|
|
140
|
+
},
|
|
141
|
+
proxyHost: {
|
|
142
|
+
type: 'string',
|
|
143
|
+
description: 'Proxy server host/IP address (optional)',
|
|
144
|
+
},
|
|
145
|
+
proxyPort: {
|
|
146
|
+
type: 'string',
|
|
147
|
+
description: 'Proxy server port (optional)',
|
|
148
|
+
},
|
|
149
|
+
proxyUserName: {
|
|
150
|
+
type: 'string',
|
|
151
|
+
description: 'Proxy username (optional)',
|
|
152
|
+
},
|
|
153
|
+
proxyPassword: {
|
|
154
|
+
type: 'string',
|
|
155
|
+
description: 'Proxy password (optional)',
|
|
156
|
+
},
|
|
157
|
+
proxyType: {
|
|
158
|
+
type: 'string',
|
|
159
|
+
enum: ['HTTP', 'HTTPS', 'SOCKS5'],
|
|
160
|
+
description: 'Proxy type (optional, default: HTTP)',
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
required: ['workspaceId'],
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: 'roxy_create_browser_standard',
|
|
168
|
+
description: 'Create a browser with standard configuration - covers most common use cases',
|
|
169
|
+
inputSchema: {
|
|
170
|
+
type: 'object',
|
|
171
|
+
properties: {
|
|
172
|
+
workspaceId: {
|
|
173
|
+
type: 'number',
|
|
174
|
+
description: 'Workspace ID (required)',
|
|
175
|
+
},
|
|
176
|
+
windowName: {
|
|
177
|
+
type: 'string',
|
|
178
|
+
description: 'Browser window name (optional)',
|
|
179
|
+
},
|
|
180
|
+
projectId: {
|
|
181
|
+
type: 'number',
|
|
182
|
+
description: 'Project ID (optional)',
|
|
183
|
+
},
|
|
184
|
+
windowRemark: {
|
|
185
|
+
type: 'string',
|
|
186
|
+
description: 'Window remarks/notes (optional)',
|
|
187
|
+
},
|
|
188
|
+
os: {
|
|
189
|
+
type: 'string',
|
|
190
|
+
enum: ['Windows', 'macOS', 'Linux', 'IOS', 'Android'],
|
|
191
|
+
description: 'Operating system (optional, default: Windows)',
|
|
192
|
+
},
|
|
193
|
+
osVersion: {
|
|
194
|
+
type: 'string',
|
|
195
|
+
description: 'OS version (optional, auto-selected based on OS)',
|
|
196
|
+
},
|
|
197
|
+
coreVersion: {
|
|
198
|
+
type: 'string',
|
|
199
|
+
enum: ['138', '137', '136', '135', '133', '130', '125', '117', '109'],
|
|
200
|
+
description: 'Browser core version (optional, default: 125)',
|
|
201
|
+
},
|
|
202
|
+
proxyInfo: {
|
|
203
|
+
type: 'object',
|
|
204
|
+
description: 'Complete proxy configuration object (optional)',
|
|
205
|
+
properties: {
|
|
206
|
+
proxyMethod: { type: 'string', enum: ['custom', 'choose', 'api'] },
|
|
207
|
+
proxyCategory: { type: 'string', enum: ['noproxy', 'HTTP', 'HTTPS', 'SOCKS5', 'SSH'] },
|
|
208
|
+
ipType: { type: 'string', enum: ['IPV4', 'IPV6'] },
|
|
209
|
+
protocol: { type: 'string', enum: ['HTTP', 'HTTPS', 'SOCKS5'] },
|
|
210
|
+
host: { type: 'string' },
|
|
211
|
+
port: { type: 'string' },
|
|
212
|
+
proxyUserName: { type: 'string' },
|
|
213
|
+
proxyPassword: { type: 'string' },
|
|
214
|
+
refreshUrl: { type: 'string' },
|
|
215
|
+
checkChannel: { type: 'string', enum: ['IPRust.io', 'IP-API', 'IP123.in'] },
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
openWidth: {
|
|
219
|
+
type: 'string',
|
|
220
|
+
description: 'Browser window width (optional, default: 1000)',
|
|
221
|
+
},
|
|
222
|
+
openHeight: {
|
|
223
|
+
type: 'string',
|
|
224
|
+
description: 'Browser window height (optional, default: 1000)',
|
|
225
|
+
},
|
|
226
|
+
language: {
|
|
227
|
+
type: 'string',
|
|
228
|
+
description: 'Browser language (optional, e.g., en-US)',
|
|
229
|
+
},
|
|
230
|
+
timeZone: {
|
|
231
|
+
type: 'string',
|
|
232
|
+
description: 'Browser timezone (optional, e.g., GMT-5:00 America/New_York)',
|
|
233
|
+
},
|
|
234
|
+
defaultOpenUrl: {
|
|
235
|
+
type: 'array',
|
|
236
|
+
items: { type: 'string' },
|
|
237
|
+
description: 'URLs to open by default (optional)',
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
required: ['workspaceId'],
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
name: 'roxy_create_browser_advanced',
|
|
245
|
+
description: 'Create a browser with complete configuration control - for expert users',
|
|
246
|
+
inputSchema: {
|
|
247
|
+
type: 'object',
|
|
248
|
+
properties: {
|
|
249
|
+
workspaceId: {
|
|
250
|
+
type: 'number',
|
|
251
|
+
description: 'Workspace ID (required)',
|
|
252
|
+
},
|
|
253
|
+
windowName: {
|
|
254
|
+
type: 'string',
|
|
255
|
+
description: 'Browser window name (optional)',
|
|
256
|
+
},
|
|
257
|
+
projectId: {
|
|
258
|
+
type: 'number',
|
|
259
|
+
description: 'Project ID (optional)',
|
|
260
|
+
},
|
|
261
|
+
windowRemark: {
|
|
262
|
+
type: 'string',
|
|
263
|
+
description: 'Window remarks (optional)',
|
|
264
|
+
},
|
|
265
|
+
os: {
|
|
266
|
+
type: 'string',
|
|
267
|
+
enum: ['Windows', 'macOS', 'Linux', 'IOS', 'Android'],
|
|
268
|
+
description: 'Operating system (optional)',
|
|
269
|
+
},
|
|
270
|
+
osVersion: {
|
|
271
|
+
type: 'string',
|
|
272
|
+
description: 'OS version (optional)',
|
|
273
|
+
},
|
|
274
|
+
coreVersion: {
|
|
275
|
+
type: 'string',
|
|
276
|
+
enum: ['138', '137', '136', '135', '133', '130', '125', '117', '109'],
|
|
277
|
+
description: 'Browser core version (optional)',
|
|
278
|
+
},
|
|
279
|
+
userAgent: {
|
|
280
|
+
type: 'string',
|
|
281
|
+
description: 'Custom user agent (optional)',
|
|
282
|
+
},
|
|
283
|
+
searchEngine: {
|
|
284
|
+
type: 'string',
|
|
285
|
+
enum: ['Google', 'Microsoft Bing', 'Yahoo', 'Yandex', 'DuckDuckGo'],
|
|
286
|
+
description: 'Default search engine (optional)',
|
|
287
|
+
},
|
|
288
|
+
labelIds: {
|
|
289
|
+
type: 'array',
|
|
290
|
+
items: { type: 'number' },
|
|
291
|
+
description: 'Label IDs to assign (optional)',
|
|
292
|
+
},
|
|
293
|
+
defaultOpenUrl: {
|
|
294
|
+
type: 'array',
|
|
295
|
+
items: { type: 'string' },
|
|
296
|
+
description: 'Default URLs to open (optional)',
|
|
297
|
+
},
|
|
298
|
+
proxyInfo: {
|
|
299
|
+
type: 'object',
|
|
300
|
+
description: 'Proxy configuration (optional)',
|
|
301
|
+
},
|
|
302
|
+
fingerInfo: {
|
|
303
|
+
type: 'object',
|
|
304
|
+
description: 'Complete fingerprint configuration (optional)',
|
|
305
|
+
},
|
|
306
|
+
windowPlatformList: {
|
|
307
|
+
type: 'array',
|
|
308
|
+
items: { type: 'object' },
|
|
309
|
+
description: 'Platform account information (optional)',
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
required: ['workspaceId'],
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
name: 'roxy_create_browser_from_template',
|
|
317
|
+
description: 'Create browsers using predefined templates - perfect for batch creation and common scenarios',
|
|
318
|
+
inputSchema: {
|
|
319
|
+
type: 'object',
|
|
320
|
+
properties: {
|
|
321
|
+
workspaceId: {
|
|
322
|
+
type: 'number',
|
|
323
|
+
description: 'Workspace ID (required)',
|
|
324
|
+
},
|
|
325
|
+
templateName: {
|
|
326
|
+
type: 'string',
|
|
327
|
+
enum: ['gmail', 'facebook', 'ecommerce', 'social_media', 'general', 'custom'],
|
|
328
|
+
description: 'Template to use (required)',
|
|
329
|
+
},
|
|
330
|
+
count: {
|
|
331
|
+
type: 'number',
|
|
332
|
+
description: 'Number of browsers to create (optional, default: 1)',
|
|
333
|
+
minimum: 1,
|
|
334
|
+
maximum: 50,
|
|
335
|
+
},
|
|
336
|
+
namePrefix: {
|
|
337
|
+
type: 'string',
|
|
338
|
+
description: 'Prefix for browser names (optional)',
|
|
339
|
+
},
|
|
340
|
+
projectId: {
|
|
341
|
+
type: 'number',
|
|
342
|
+
description: 'Project ID (optional)',
|
|
343
|
+
},
|
|
344
|
+
proxyList: {
|
|
345
|
+
type: 'array',
|
|
346
|
+
items: { type: 'object' },
|
|
347
|
+
description: 'List of proxy configurations to distribute across browsers (optional)',
|
|
348
|
+
},
|
|
349
|
+
customConfig: {
|
|
350
|
+
type: 'object',
|
|
351
|
+
description: 'Custom configuration to override template defaults (optional)',
|
|
352
|
+
},
|
|
353
|
+
},
|
|
354
|
+
required: ['workspaceId', 'templateName'],
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
name: 'roxy_list_browser_templates',
|
|
359
|
+
description: 'List available browser templates with descriptions',
|
|
360
|
+
inputSchema: {
|
|
361
|
+
type: 'object',
|
|
362
|
+
properties: {},
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
name: 'roxy_validate_proxy_config',
|
|
367
|
+
description: 'Validate proxy configuration before using it',
|
|
368
|
+
inputSchema: {
|
|
369
|
+
type: 'object',
|
|
370
|
+
properties: {
|
|
371
|
+
proxyInfo: {
|
|
372
|
+
type: 'object',
|
|
373
|
+
description: 'Proxy configuration to validate (required)',
|
|
374
|
+
properties: {
|
|
375
|
+
proxyMethod: { type: 'string', enum: ['custom', 'choose', 'api'] },
|
|
376
|
+
proxyCategory: { type: 'string', enum: ['noproxy', 'HTTP', 'HTTPS', 'SOCKS5', 'SSH'] },
|
|
377
|
+
ipType: { type: 'string', enum: ['IPV4', 'IPV6'] },
|
|
378
|
+
protocol: { type: 'string', enum: ['HTTP', 'HTTPS', 'SOCKS5'] },
|
|
379
|
+
host: { type: 'string' },
|
|
380
|
+
port: { type: 'string' },
|
|
381
|
+
proxyUserName: { type: 'string' },
|
|
382
|
+
proxyPassword: { type: 'string' },
|
|
383
|
+
refreshUrl: { type: 'string' },
|
|
384
|
+
checkChannel: { type: 'string', enum: ['IPRust.io', 'IP-API', 'IP123.in'] },
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
required: ['proxyInfo'],
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
];
|
|
392
|
+
// ========== MCP Server ==========
|
|
393
|
+
class RoxyBrowserMCPServer {
|
|
394
|
+
server;
|
|
395
|
+
roxyClient;
|
|
396
|
+
constructor() {
|
|
397
|
+
this.server = new Server({
|
|
398
|
+
name: 'roxy-browser-mcp',
|
|
399
|
+
version: '1.0.0',
|
|
400
|
+
}, {
|
|
401
|
+
capabilities: {
|
|
402
|
+
tools: {},
|
|
403
|
+
},
|
|
404
|
+
});
|
|
405
|
+
// Initialize RoxyBrowser client
|
|
406
|
+
const config = getConfig();
|
|
407
|
+
this.roxyClient = new RoxyClient(config);
|
|
408
|
+
this.setupHandlers();
|
|
409
|
+
}
|
|
410
|
+
setupHandlers() {
|
|
411
|
+
// List available tools
|
|
412
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
413
|
+
tools: TOOLS,
|
|
414
|
+
}));
|
|
415
|
+
// Handle tool calls
|
|
416
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
417
|
+
const { name, arguments: args } = request.params;
|
|
418
|
+
try {
|
|
419
|
+
switch (name) {
|
|
420
|
+
case 'roxy_list_workspaces':
|
|
421
|
+
return await this.handleListWorkspaces(args);
|
|
422
|
+
case 'roxy_list_browsers':
|
|
423
|
+
return await this.handleListBrowsers(args);
|
|
424
|
+
case 'roxy_open_browsers':
|
|
425
|
+
return await this.handleOpenBrowsers(args);
|
|
426
|
+
case 'roxy_close_browsers':
|
|
427
|
+
return await this.handleCloseBrowsers(args);
|
|
428
|
+
case 'roxy_create_browser_simple':
|
|
429
|
+
return await this.handleCreateBrowserSimple(args);
|
|
430
|
+
case 'roxy_create_browser_standard':
|
|
431
|
+
return await this.handleCreateBrowserStandard(args);
|
|
432
|
+
case 'roxy_create_browser_advanced':
|
|
433
|
+
return await this.handleCreateBrowserAdvanced(args);
|
|
434
|
+
case 'roxy_create_browser_from_template':
|
|
435
|
+
return await this.handleCreateBrowserFromTemplate(args);
|
|
436
|
+
case 'roxy_list_browser_templates':
|
|
437
|
+
return await this.handleListBrowserTemplates();
|
|
438
|
+
case 'roxy_validate_proxy_config':
|
|
439
|
+
return await this.handleValidateProxyConfig(args);
|
|
440
|
+
default:
|
|
441
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
catch (error) {
|
|
445
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
446
|
+
return {
|
|
447
|
+
content: [
|
|
448
|
+
{
|
|
449
|
+
type: 'text',
|
|
450
|
+
text: `Error: ${errorMessage}`,
|
|
451
|
+
},
|
|
452
|
+
],
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
async handleCreateBrowserSimple(args) {
|
|
458
|
+
const params = args;
|
|
459
|
+
if (!params.workspaceId) {
|
|
460
|
+
throw new Error('workspaceId is required');
|
|
461
|
+
}
|
|
462
|
+
// Build configuration from simple parameters
|
|
463
|
+
const config = BrowserCreator.buildSimpleConfig(params);
|
|
464
|
+
const finalConfig = BrowserCreator.applyDefaults(config);
|
|
465
|
+
// Validate configuration
|
|
466
|
+
const validation = BrowserCreator.validateConfig(finalConfig);
|
|
467
|
+
if (!validation.valid) {
|
|
468
|
+
throw new BrowserCreationError(`Configuration validation failed: ${validation.errors.join(', ')}`);
|
|
469
|
+
}
|
|
470
|
+
// Create browser
|
|
471
|
+
const result = await this.roxyClient.createBrowser(finalConfig);
|
|
472
|
+
const response = {
|
|
473
|
+
browser: {
|
|
474
|
+
dirId: result.dirId,
|
|
475
|
+
windowName: finalConfig.windowName || 'Simple Browser',
|
|
476
|
+
workspaceId: params.workspaceId,
|
|
477
|
+
projectId: params.projectId,
|
|
478
|
+
proxyConfigured: !!(params.proxyHost && params.proxyPort),
|
|
479
|
+
},
|
|
480
|
+
message: `Browser created successfully with ID: ${result.dirId}`,
|
|
481
|
+
};
|
|
482
|
+
return {
|
|
483
|
+
content: [
|
|
484
|
+
{
|
|
485
|
+
type: 'text',
|
|
486
|
+
text: `✅ **Simple Browser Created**\n\n` +
|
|
487
|
+
`**Browser ID:** \`${response.browser.dirId}\`\n` +
|
|
488
|
+
`**Name:** ${response.browser.windowName}\n` +
|
|
489
|
+
`**Workspace:** ${response.browser.workspaceId}\n` +
|
|
490
|
+
`${response.browser.projectId ? `**Project:** ${response.browser.projectId}\n` : ''}` +
|
|
491
|
+
`**Proxy:** ${response.browser.proxyConfigured ? '✅ Configured' : '❌ Not configured'}\n\n` +
|
|
492
|
+
`*Use this browser ID with \`roxy_open_browsers\` to start the browser and get CDP endpoints for automation.*`,
|
|
493
|
+
},
|
|
494
|
+
],
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
async handleCreateBrowserStandard(args) {
|
|
498
|
+
const params = args;
|
|
499
|
+
if (!params.workspaceId) {
|
|
500
|
+
throw new Error('workspaceId is required');
|
|
501
|
+
}
|
|
502
|
+
// Build configuration from standard parameters
|
|
503
|
+
const config = BrowserCreator.buildStandardConfig(params);
|
|
504
|
+
const finalConfig = BrowserCreator.applyDefaults(config);
|
|
505
|
+
// Validate configuration
|
|
506
|
+
const validation = BrowserCreator.validateConfig(finalConfig);
|
|
507
|
+
if (!validation.valid) {
|
|
508
|
+
throw new BrowserCreationError(`Configuration validation failed: ${validation.errors.join(', ')}`);
|
|
509
|
+
}
|
|
510
|
+
// Create browser
|
|
511
|
+
const result = await this.roxyClient.createBrowser(finalConfig);
|
|
512
|
+
const response = {
|
|
513
|
+
browser: {
|
|
514
|
+
dirId: result.dirId,
|
|
515
|
+
windowName: finalConfig.windowName || 'Standard Browser',
|
|
516
|
+
workspaceId: params.workspaceId,
|
|
517
|
+
projectId: params.projectId,
|
|
518
|
+
os: finalConfig.os || 'Windows',
|
|
519
|
+
coreVersion: finalConfig.coreVersion || '125',
|
|
520
|
+
proxyInfo: params.proxyInfo,
|
|
521
|
+
windowSize: `${params.openWidth || '1000'}x${params.openHeight || '1000'}`,
|
|
522
|
+
},
|
|
523
|
+
message: `Standard browser created successfully with ID: ${result.dirId}`,
|
|
524
|
+
};
|
|
525
|
+
return {
|
|
526
|
+
content: [
|
|
527
|
+
{
|
|
528
|
+
type: 'text',
|
|
529
|
+
text: `✅ **Standard Browser Created**\n\n` +
|
|
530
|
+
`**Browser ID:** \`${response.browser.dirId}\`\n` +
|
|
531
|
+
`**Name:** ${response.browser.windowName}\n` +
|
|
532
|
+
`**OS:** ${response.browser.os} ${finalConfig.osVersion || ''}\n` +
|
|
533
|
+
`**Core Version:** ${response.browser.coreVersion}\n` +
|
|
534
|
+
`**Window Size:** ${response.browser.windowSize}\n` +
|
|
535
|
+
`**Workspace:** ${response.browser.workspaceId}\n` +
|
|
536
|
+
`${response.browser.projectId ? `**Project:** ${response.browser.projectId}\n` : ''}` +
|
|
537
|
+
`**Proxy:** ${response.browser.proxyInfo ? '✅ Configured' : '❌ Not configured'}\n\n` +
|
|
538
|
+
`*Browser is ready for automation. Use \`roxy_open_browsers\` to start it.*`,
|
|
539
|
+
},
|
|
540
|
+
],
|
|
541
|
+
};
|
|
542
|
+
}
|
|
543
|
+
async handleCreateBrowserAdvanced(args) {
|
|
544
|
+
const params = args;
|
|
545
|
+
if (!params.workspaceId) {
|
|
546
|
+
throw new Error('workspaceId is required');
|
|
547
|
+
}
|
|
548
|
+
// Build configuration from advanced parameters
|
|
549
|
+
const config = BrowserCreator.buildAdvancedConfig(params);
|
|
550
|
+
const finalConfig = BrowserCreator.applyDefaults(config);
|
|
551
|
+
// Validate configuration
|
|
552
|
+
const validation = BrowserCreator.validateConfig(finalConfig);
|
|
553
|
+
if (!validation.valid) {
|
|
554
|
+
throw new BrowserCreationError(`Configuration validation failed: ${validation.errors.join(', ')}`);
|
|
555
|
+
}
|
|
556
|
+
// Create browser
|
|
557
|
+
const result = await this.roxyClient.createBrowser(finalConfig);
|
|
558
|
+
const response = {
|
|
559
|
+
browser: {
|
|
560
|
+
dirId: result.dirId,
|
|
561
|
+
config: finalConfig,
|
|
562
|
+
},
|
|
563
|
+
message: `Advanced browser created successfully with ID: ${result.dirId}`,
|
|
564
|
+
};
|
|
565
|
+
// Create detailed status text
|
|
566
|
+
const configSummary = [
|
|
567
|
+
`**Browser ID:** \`${response.browser.dirId}\``,
|
|
568
|
+
`**Name:** ${finalConfig.windowName || 'Advanced Browser'}`,
|
|
569
|
+
`**OS:** ${finalConfig.os || 'Windows'} ${finalConfig.osVersion || ''}`,
|
|
570
|
+
`**Core Version:** ${finalConfig.coreVersion || '125'}`,
|
|
571
|
+
finalConfig.userAgent ? `**User Agent:** ${finalConfig.userAgent.substring(0, 50)}...` : '',
|
|
572
|
+
`**Search Engine:** ${finalConfig.searchEngine || 'Google'}`,
|
|
573
|
+
finalConfig.proxyInfo?.proxyCategory !== 'noproxy' ? `**Proxy:** ✅ ${finalConfig.proxyInfo?.proxyCategory} ${finalConfig.proxyInfo?.host}:${finalConfig.proxyInfo?.port}` : '**Proxy:** ❌ No proxy',
|
|
574
|
+
finalConfig.fingerInfo?.randomFingerprint ? '**Fingerprint:** 🎲 Random' : '**Fingerprint:** 🔒 Fixed',
|
|
575
|
+
finalConfig.defaultOpenUrl?.length ? `**Default URLs:** ${finalConfig.defaultOpenUrl.length} URL(s)` : '',
|
|
576
|
+
].filter(Boolean).join('\n');
|
|
577
|
+
return {
|
|
578
|
+
content: [
|
|
579
|
+
{
|
|
580
|
+
type: 'text',
|
|
581
|
+
text: `✅ **Advanced Browser Created**\n\n${configSummary}\n\n` +
|
|
582
|
+
`*Advanced browser configured with complete control. Use \`roxy_open_browsers\` to start it.*`,
|
|
583
|
+
},
|
|
584
|
+
],
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
async handleCreateBrowserFromTemplate(args) {
|
|
588
|
+
const params = args;
|
|
589
|
+
if (!params.workspaceId || !params.templateName) {
|
|
590
|
+
throw new Error('workspaceId and templateName are required');
|
|
591
|
+
}
|
|
592
|
+
// Get template configuration
|
|
593
|
+
const templateConfig = TemplateManager.getTemplateConfig(params.templateName, params.customConfig);
|
|
594
|
+
// Build configurations for multiple browsers
|
|
595
|
+
const configs = BrowserCreator.buildConfigsFromTemplate(params, templateConfig);
|
|
596
|
+
// Validate all configurations
|
|
597
|
+
const validation = BrowserCreator.validateConfigs(configs);
|
|
598
|
+
if (!validation.valid) {
|
|
599
|
+
const errorDetails = validation.errors.map(err => `Browser ${err.index + 1}: ${err.errors.join(', ')}`).join('\n');
|
|
600
|
+
throw new BrowserCreationError(`Configuration validation failed:\n${errorDetails}`);
|
|
601
|
+
}
|
|
602
|
+
// Create browsers in batch
|
|
603
|
+
const batchResult = await this.roxyClient.createBrowsers(configs);
|
|
604
|
+
const response = {
|
|
605
|
+
browsers: batchResult.results,
|
|
606
|
+
template: params.templateName,
|
|
607
|
+
successCount: batchResult.successCount,
|
|
608
|
+
failureCount: batchResult.failureCount,
|
|
609
|
+
total: batchResult.total,
|
|
610
|
+
message: `Template-based creation completed: ${batchResult.successCount}/${batchResult.total} browsers created successfully`,
|
|
611
|
+
};
|
|
612
|
+
// Create result summary
|
|
613
|
+
const successBrowsers = batchResult.results.filter(r => r.success);
|
|
614
|
+
const failedBrowsers = batchResult.results.filter(r => !r.success);
|
|
615
|
+
let resultText = `✅ **Template Browser Creation Complete**\n\n` +
|
|
616
|
+
`**Template:** ${params.templateName}\n` +
|
|
617
|
+
`**Success:** ${response.successCount}/${response.total}\n` +
|
|
618
|
+
`**Workspace:** ${params.workspaceId}\n` +
|
|
619
|
+
`${params.projectId ? `**Project:** ${params.projectId}\n` : ''}\n`;
|
|
620
|
+
if (successBrowsers.length > 0) {
|
|
621
|
+
resultText += `**✅ Successfully Created (${successBrowsers.length}):**\n`;
|
|
622
|
+
successBrowsers.forEach((browser, index) => {
|
|
623
|
+
resultText += ` ${index + 1}. \`${browser.dirId}\` - ${browser.windowName}\n`;
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
if (failedBrowsers.length > 0) {
|
|
627
|
+
resultText += `\n**❌ Failed (${failedBrowsers.length}):**\n`;
|
|
628
|
+
failedBrowsers.forEach((browser, index) => {
|
|
629
|
+
resultText += ` ${index + 1}. ${browser.windowName} - ${browser.error}\n`;
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
resultText += `\n*Use \`roxy_open_browsers\` with the successful browser IDs to start them for automation.*`;
|
|
633
|
+
return {
|
|
634
|
+
content: [
|
|
635
|
+
{
|
|
636
|
+
type: 'text',
|
|
637
|
+
text: resultText,
|
|
638
|
+
},
|
|
639
|
+
],
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
async handleListBrowserTemplates() {
|
|
643
|
+
const templates = TemplateManager.getAvailableTemplates();
|
|
644
|
+
const templateText = templates.map(template => `**${template.name}**\n ${template.description}`).join('\n\n');
|
|
645
|
+
return {
|
|
646
|
+
content: [
|
|
647
|
+
{
|
|
648
|
+
type: 'text',
|
|
649
|
+
text: `📋 **Available Browser Templates**\n\n${templateText}\n\n` +
|
|
650
|
+
`*Use these template names with \`roxy_create_browser_from_template\` for optimized browser configurations.*`,
|
|
651
|
+
},
|
|
652
|
+
],
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
async handleValidateProxyConfig(args) {
|
|
656
|
+
const { proxyInfo } = args;
|
|
657
|
+
if (!proxyInfo) {
|
|
658
|
+
throw new Error('proxyInfo is required');
|
|
659
|
+
}
|
|
660
|
+
const validation = ProxyManager.validateProxy(proxyInfo);
|
|
661
|
+
let resultText = '';
|
|
662
|
+
if (validation.valid) {
|
|
663
|
+
resultText = `✅ **Proxy Configuration Valid**\n\n` +
|
|
664
|
+
`**Type:** ${proxyInfo.proxyCategory || 'Not specified'}\n` +
|
|
665
|
+
`**Host:** ${proxyInfo.host || 'Not specified'}\n` +
|
|
666
|
+
`**Port:** ${proxyInfo.port || 'Not specified'}\n` +
|
|
667
|
+
`**Authentication:** ${proxyInfo.proxyUserName ? '✅ Yes' : '❌ No'}\n` +
|
|
668
|
+
`**IP Type:** ${proxyInfo.ipType || 'IPV4'}`;
|
|
669
|
+
}
|
|
670
|
+
else {
|
|
671
|
+
resultText = `❌ **Proxy Configuration Invalid**\n\n` +
|
|
672
|
+
`**Errors:**\n` +
|
|
673
|
+
validation.errors.map(error => ` • ${error}`).join('\n');
|
|
674
|
+
}
|
|
675
|
+
if (validation.warnings.length > 0) {
|
|
676
|
+
resultText += `\n\n**⚠️ Warnings:**\n` +
|
|
677
|
+
validation.warnings.map(warning => ` • ${warning}`).join('\n');
|
|
678
|
+
}
|
|
679
|
+
return {
|
|
680
|
+
content: [
|
|
681
|
+
{
|
|
682
|
+
type: 'text',
|
|
683
|
+
text: resultText,
|
|
684
|
+
},
|
|
685
|
+
],
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
async handleListWorkspaces(args) {
|
|
689
|
+
const { pageIndex = 1, pageSize = 15 } = args || {};
|
|
690
|
+
const data = await this.roxyClient.getWorkspaces(pageIndex, pageSize);
|
|
691
|
+
return {
|
|
692
|
+
content: [
|
|
693
|
+
{
|
|
694
|
+
type: 'text',
|
|
695
|
+
text: `Found ${data.total} workspaces:\n\n` +
|
|
696
|
+
data.rows.map(ws => `**${ws.workspaceName}** (ID: ${ws.id})\n` +
|
|
697
|
+
ws.project_details.map(proj => ` - ${proj.projectName} (ID: ${proj.projectId})`).join('\n')).join('\n\n'),
|
|
698
|
+
},
|
|
699
|
+
],
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
async handleListBrowsers(args) {
|
|
703
|
+
const params = args;
|
|
704
|
+
if (!params.workspaceId) {
|
|
705
|
+
throw new Error('workspaceId is required');
|
|
706
|
+
}
|
|
707
|
+
const data = await this.roxyClient.getBrowsers({
|
|
708
|
+
workspaceId: params.workspaceId,
|
|
709
|
+
projectIds: params.projectIds,
|
|
710
|
+
windowName: params.windowName,
|
|
711
|
+
page_index: params.pageIndex || 1,
|
|
712
|
+
page_size: params.pageSize || 15,
|
|
713
|
+
});
|
|
714
|
+
return {
|
|
715
|
+
content: [
|
|
716
|
+
{
|
|
717
|
+
type: 'text',
|
|
718
|
+
text: `Found ${data.total} browsers in workspace ${params.workspaceId}:\n\n` +
|
|
719
|
+
data.rows.map(browser => `**${browser.windowName || 'Unnamed'}** (ID: ${browser.dirId})\n` +
|
|
720
|
+
` - Project: ${browser.projectId}\n` +
|
|
721
|
+
` - Sort: ${browser.sortNum}\n` +
|
|
722
|
+
` - OS: ${browser.os}\n` +
|
|
723
|
+
` - Status: ${browser.status}`).join('\n\n'),
|
|
724
|
+
},
|
|
725
|
+
],
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
async handleOpenBrowsers(args) {
|
|
729
|
+
const params = args;
|
|
730
|
+
if (!params.workspaceId || !params.dirIds || params.dirIds.length === 0) {
|
|
731
|
+
throw new Error('workspaceId and dirIds are required');
|
|
732
|
+
}
|
|
733
|
+
const results = await this.roxyClient.openBrowsers(params.workspaceId, params.dirIds, params.args);
|
|
734
|
+
return {
|
|
735
|
+
content: [
|
|
736
|
+
{
|
|
737
|
+
type: 'text',
|
|
738
|
+
text: `Successfully opened ${results.length} browsers:\n\n` +
|
|
739
|
+
results.map(result => `**Browser ${result.dirId || 'Unknown'}** (PID: ${result.pid})\n` +
|
|
740
|
+
` - CDP WebSocket: \`${result.ws}\`\n` +
|
|
741
|
+
` - HTTP Endpoint: \`${result.http}\`\n` +
|
|
742
|
+
` - Core Version: ${result.coreVersion}`).join('\n\n') +
|
|
743
|
+
'\n\n**Use these WebSocket URLs with playwright-mcp:**\n' +
|
|
744
|
+
'```bash\n' +
|
|
745
|
+
results.map(result => `npx @playwright/mcp@latest --cdp-endpoint "${result.ws}"`).join('\n') +
|
|
746
|
+
'\n```',
|
|
747
|
+
},
|
|
748
|
+
],
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
async handleCloseBrowsers(args) {
|
|
752
|
+
const params = args;
|
|
753
|
+
if (!params.dirIds || params.dirIds.length === 0) {
|
|
754
|
+
throw new Error('dirIds are required');
|
|
755
|
+
}
|
|
756
|
+
const results = await this.roxyClient.closeBrowsers(params.dirIds);
|
|
757
|
+
const successCount = results.filter(r => r.success).length;
|
|
758
|
+
const failureCount = results.filter(r => !r.success).length;
|
|
759
|
+
const successText = successCount > 0
|
|
760
|
+
? `✅ Successfully closed ${successCount} browsers`
|
|
761
|
+
: '';
|
|
762
|
+
const failureText = failureCount > 0
|
|
763
|
+
? `❌ Failed to close ${failureCount} browsers:\n` +
|
|
764
|
+
results.filter(r => !r.success).map(r => ` - ${r.dirId}: ${r.error}`).join('\n')
|
|
765
|
+
: '';
|
|
766
|
+
return {
|
|
767
|
+
content: [
|
|
768
|
+
{
|
|
769
|
+
type: 'text',
|
|
770
|
+
text: [successText, failureText].filter(Boolean).join('\n\n'),
|
|
771
|
+
},
|
|
772
|
+
],
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
async run() {
|
|
776
|
+
// Test connection before starting
|
|
777
|
+
console.error('🔗 Testing RoxyBrowser API connection...');
|
|
778
|
+
const isConnected = await this.roxyClient.testConnection();
|
|
779
|
+
if (!isConnected) {
|
|
780
|
+
console.error('❌ Failed to connect to RoxyBrowser API');
|
|
781
|
+
console.error(' Please check:');
|
|
782
|
+
console.error(' 1. RoxyBrowser is running');
|
|
783
|
+
console.error(' 2. API is enabled in RoxyBrowser settings');
|
|
784
|
+
console.error(' 3. ROXY_API_KEY environment variable is set');
|
|
785
|
+
console.error(' 4. API host is correct (default: http://127.0.0.1:50000)');
|
|
786
|
+
process.exit(1);
|
|
787
|
+
}
|
|
788
|
+
console.error('✅ Connected to RoxyBrowser API');
|
|
789
|
+
console.error('🚀 Starting RoxyBrowser MCP Server...');
|
|
790
|
+
const transport = new StdioServerTransport();
|
|
791
|
+
await this.server.connect(transport);
|
|
792
|
+
console.error('✅ RoxyBrowser MCP Server is running');
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
// ========== Main ==========
|
|
796
|
+
async function main() {
|
|
797
|
+
try {
|
|
798
|
+
const server = new RoxyBrowserMCPServer();
|
|
799
|
+
await server.run();
|
|
800
|
+
}
|
|
801
|
+
catch (error) {
|
|
802
|
+
if (error instanceof ConfigError) {
|
|
803
|
+
console.error(`❌ Configuration Error: ${error.message}`);
|
|
804
|
+
process.exit(1);
|
|
805
|
+
}
|
|
806
|
+
console.error('❌ Unexpected error:', error);
|
|
807
|
+
process.exit(1);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
// Handle graceful shutdown
|
|
811
|
+
process.on('SIGINT', () => {
|
|
812
|
+
console.error('\n👋 Shutting down RoxyBrowser MCP Server...');
|
|
813
|
+
process.exit(0);
|
|
814
|
+
});
|
|
815
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
816
|
+
main().catch((error) => {
|
|
817
|
+
console.error('Fatal error:', error);
|
|
818
|
+
process.exit(1);
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
//# sourceMappingURL=index.js.map
|