@roxybrowser/openapi 1.0.5-beta.1 → 1.0.8

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 (48) hide show
  1. package/README.md +222 -228
  2. package/lib/index.js +97 -1674
  3. package/lib/index.js.map +1 -1
  4. package/lib/modules/account.d.ts +491 -0
  5. package/lib/modules/account.d.ts.map +1 -0
  6. package/lib/modules/account.js +442 -0
  7. package/lib/modules/account.js.map +1 -0
  8. package/lib/modules/browser.d.ts +3011 -0
  9. package/lib/modules/browser.d.ts.map +1 -0
  10. package/lib/modules/browser.js +1501 -0
  11. package/lib/modules/browser.js.map +1 -0
  12. package/lib/modules/other.d.ts +102 -0
  13. package/lib/modules/other.d.ts.map +1 -0
  14. package/lib/modules/other.js +194 -0
  15. package/lib/modules/other.js.map +1 -0
  16. package/lib/modules/proxy.d.ts +576 -0
  17. package/lib/modules/proxy.d.ts.map +1 -0
  18. package/lib/modules/proxy.js +724 -0
  19. package/lib/modules/proxy.js.map +1 -0
  20. package/lib/types.d.ts +860 -155
  21. package/lib/types.d.ts.map +1 -1
  22. package/lib/types.js +4 -4
  23. package/lib/types.js.map +1 -1
  24. package/lib/utils/index.d.ts +24 -0
  25. package/lib/utils/index.d.ts.map +1 -0
  26. package/lib/utils/index.js +45 -0
  27. package/lib/utils/index.js.map +1 -0
  28. package/package.json +50 -50
  29. package/lib/browser/browser-creator.d.ts +0 -54
  30. package/lib/browser/browser-creator.d.ts.map +0 -1
  31. package/lib/browser/browser-creator.js +0 -263
  32. package/lib/browser/browser-creator.js.map +0 -1
  33. package/lib/proxy/proxy-manager.d.ts +0 -67
  34. package/lib/proxy/proxy-manager.d.ts.map +0 -1
  35. package/lib/proxy/proxy-manager.js +0 -278
  36. package/lib/proxy/proxy-manager.js.map +0 -1
  37. package/lib/proxy/proxy-validator.d.ts +0 -66
  38. package/lib/proxy/proxy-validator.d.ts.map +0 -1
  39. package/lib/proxy/proxy-validator.js +0 -273
  40. package/lib/proxy/proxy-validator.js.map +0 -1
  41. package/lib/roxy-client.d.ts +0 -117
  42. package/lib/roxy-client.d.ts.map +0 -1
  43. package/lib/roxy-client.js +0 -467
  44. package/lib/roxy-client.js.map +0 -1
  45. package/lib/utils/error-analyzer.d.ts +0 -84
  46. package/lib/utils/error-analyzer.d.ts.map +0 -1
  47. package/lib/utils/error-analyzer.js +0 -387
  48. package/lib/utils/error-analyzer.js.map +0 -1
package/lib/index.js CHANGED
@@ -8,913 +8,58 @@
8
8
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
9
9
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
10
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 { ProxyManager } from './proxy/proxy-manager.js';
14
- import { ErrorAnalyzer } from './utils/error-analyzer.js';
15
- import { ConfigError, RoxyApiError, BrowserCreationError, LATEST_CORE_VERSION, } 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
- }
11
+ import { batchCreateAccounts, createAccount, deleteAccounts, listAccounts, modifyAccount } from './modules/account.js';
12
+ import { batchCreateBrowsers, clearLocalCache, clearServerCache, closeBrowsers, createBrowser, deleteBrowsers, getBrowserDetail, getConnectionInfo, listBrowsers, listLabels, openBrowser, randomFingerprint, updateBrowser } from './modules/browser.js';
13
+ import { healthCheck, listWorkspaces } from './modules/other.js';
14
+ import { batchCreateProxies, createProxy, deleteProxies, detectProxy, modifyProxy, proxyList, proxyStore } from './modules/proxy.js';
15
+ import { ConfigError } from './types.js';
27
16
  // ========== Tool Definitions ==========
28
17
  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_delete_browsers',
121
- description: 'Delete multiple browsers permanently by their directory IDs',
122
- inputSchema: {
123
- type: 'object',
124
- properties: {
125
- workspaceId: {
126
- type: 'number',
127
- description: 'Workspace ID (required)',
128
- },
129
- dirIds: {
130
- type: 'array',
131
- items: { type: 'string' },
132
- description: 'Array of browser directory IDs to delete (required)',
133
- },
134
- },
135
- required: ['workspaceId', 'dirIds'],
136
- },
137
- },
138
- {
139
- name: 'roxy_create_browser_simple',
140
- description: 'Create a browser with simple configuration - ideal for quick setup with basic proxy and common options',
141
- inputSchema: {
142
- type: 'object',
143
- properties: {
144
- workspaceId: {
145
- type: 'number',
146
- description: 'Workspace ID (required)',
147
- },
148
- windowName: {
149
- type: 'string',
150
- description: 'Browser window name (optional)',
151
- },
152
- projectId: {
153
- type: 'number',
154
- description: 'Project ID (optional)',
155
- },
156
- windowRemark: {
157
- type: 'string',
158
- description: 'Window remarks/notes (optional)',
159
- },
160
- proxyHost: {
161
- type: 'string',
162
- description: 'Proxy server host/IP address (optional)',
163
- },
164
- proxyPort: {
165
- type: 'string',
166
- description: 'Proxy server port (optional)',
167
- },
168
- proxyUserName: {
169
- type: 'string',
170
- description: 'Proxy username (optional)',
171
- },
172
- proxyPassword: {
173
- type: 'string',
174
- description: 'Proxy password (optional)',
175
- },
176
- proxyType: {
177
- type: 'string',
178
- enum: ['HTTP', 'HTTPS', 'SOCKS5'],
179
- description: 'Proxy type (optional, default: HTTP)',
180
- },
181
- cookie: {
182
- type: 'array',
183
- items: {
184
- type: 'object',
185
- description: 'Cookie object (e.g., { name, value, domain, path, ... })',
186
- properties: {
187
- name: { type: 'string', description: 'Cookie name' },
188
- value: { type: 'string', description: 'Cookie value' },
189
- domain: { type: 'string', description: 'Cookie domain' },
190
- path: { type: 'string', description: 'Cookie path' },
191
- expires: { type: 'number', description: 'Expiration as UNIX timestamp (seconds)' },
192
- httpOnly: { type: 'boolean', description: 'HTTP-only cookie' },
193
- secure: { type: 'boolean', description: 'Secure cookie' },
194
- sameSite: { type: 'string', description: 'SameSite policy' },
195
- },
196
- additionalProperties: true,
197
- },
198
- description: 'Cookie list (optional)',
199
- },
200
- searchEngine: {
201
- type: 'string',
202
- enum: ['Google', 'Microsoft Bing', 'Yahoo', 'Yandex', 'DuckDuckGo'],
203
- description: 'Default search engine (optional, default: Google)',
204
- },
205
- labelIds: {
206
- type: 'array',
207
- items: { type: 'number' },
208
- description: 'Label IDs to assign (optional)',
209
- },
210
- },
211
- required: ['workspaceId'],
212
- },
213
- },
214
- {
215
- name: 'roxy_create_browser_standard',
216
- description: 'Create a browser with standard configuration - covers most common use cases with commonly used fingerprint settings',
217
- inputSchema: {
218
- type: 'object',
219
- properties: {
220
- workspaceId: {
221
- type: 'number',
222
- description: 'Workspace ID (required)',
223
- },
224
- windowName: {
225
- type: 'string',
226
- description: 'Browser window name (optional)',
227
- },
228
- projectId: {
229
- type: 'number',
230
- description: 'Project ID (optional)',
231
- },
232
- windowRemark: {
233
- type: 'string',
234
- description: 'Window remarks/notes (optional)',
235
- },
236
- os: {
237
- type: 'string',
238
- enum: ['Windows', 'macOS', 'Linux', 'IOS', 'Android'],
239
- description: 'Operating system (optional, default: Windows)',
240
- },
241
- osVersion: {
242
- type: 'string',
243
- description: 'OS version (optional, auto-selected based on OS)',
244
- },
245
- coreVersion: {
246
- type: 'string',
247
- enum: ['140', '138', '137', '136', '135', '133', '130', '125', '117', '109'],
248
- description: 'Browser core version (optional, default: 140)',
249
- },
250
- userAgent: {
251
- type: 'string',
252
- description: 'Custom user agent (optional)',
253
- },
254
- cookie: {
255
- type: 'array',
256
- items: {
257
- type: 'object',
258
- description: 'Cookie object (e.g., { name, value, domain, path, ... })',
259
- properties: {
260
- name: { type: 'string', description: 'Cookie name' },
261
- value: { type: 'string', description: 'Cookie value' },
262
- domain: { type: 'string', description: 'Cookie domain' },
263
- path: { type: 'string', description: 'Cookie path' },
264
- expires: { type: 'number', description: 'Expiration as UNIX timestamp (seconds)' },
265
- httpOnly: { type: 'boolean', description: 'HTTP-only cookie' },
266
- secure: { type: 'boolean', description: 'Secure cookie' },
267
- sameSite: { type: 'string', description: 'SameSite policy' },
268
- },
269
- additionalProperties: true,
270
- },
271
- description: 'Cookie list (optional)',
272
- },
273
- searchEngine: {
274
- type: 'string',
275
- enum: ['Google', 'Microsoft Bing', 'Yahoo', 'Yandex', 'DuckDuckGo'],
276
- description: 'Default search engine (optional)',
277
- },
278
- labelIds: {
279
- type: 'array',
280
- items: { type: 'number' },
281
- description: 'Label IDs to assign (optional)',
282
- },
283
- defaultOpenUrl: {
284
- type: 'array',
285
- items: { type: 'string' },
286
- description: 'URLs to open by default (optional)',
287
- },
288
- windowPlatformList: {
289
- type: 'array',
290
- items: {
291
- type: 'object',
292
- properties: {
293
- platformUrl: { type: 'string', description: 'Platform URL' },
294
- platformUserName: { type: 'string', description: 'Platform username' },
295
- platformPassword: { type: 'string', description: 'Platform password' },
296
- platformEfa: { type: 'string', description: 'Platform EFA' },
297
- platformRemarks: { type: 'string', description: 'Platform remarks' },
298
- },
299
- },
300
- description: 'Platform account information (optional)',
301
- },
302
- proxyInfo: {
303
- type: 'object',
304
- description: 'Complete proxy configuration object (optional)',
305
- properties: {
306
- proxyMethod: { type: 'string', enum: ['custom', 'choose', 'api'] },
307
- proxyCategory: { type: 'string', enum: ['noproxy', 'HTTP', 'HTTPS', 'SOCKS5', 'SSH'] },
308
- ipType: { type: 'string', enum: ['IPV4', 'IPV6'] },
309
- protocol: { type: 'string', enum: ['HTTP', 'HTTPS', 'SOCKS5'] },
310
- host: { type: 'string' },
311
- port: { type: 'string' },
312
- proxyUserName: { type: 'string' },
313
- proxyPassword: { type: 'string' },
314
- refreshUrl: { type: 'string' },
315
- checkChannel: { type: 'string', enum: ['IPRust.io', 'IP-API', 'IP123.in'] },
316
- },
317
- },
318
- fingerInfo: {
319
- type: 'object',
320
- description: 'Common fingerprint configuration (optional) - for full control use roxy_create_browser_advanced',
321
- properties: {
322
- // Language and timezone
323
- language: { type: 'string', description: 'Browser language (e.g., en-US)' },
324
- timeZone: { type: 'string', description: 'Browser timezone (e.g., GMT-5:00 America/New_York)' },
325
- // Window settings (commonly used)
326
- openWidth: { type: 'string', description: 'Window width (default: 1000)' },
327
- openHeight: { type: 'string', description: 'Window height (default: 1000)' },
328
- // Media settings (commonly adjusted)
329
- forbidAudio: { type: 'boolean', description: 'Enable/disable sound' },
330
- forbidImage: { type: 'boolean', description: 'Enable/disable image loading' },
331
- forbidMedia: { type: 'boolean', description: 'Enable/disable video playback' },
332
- // Common fingerprint settings
333
- webRTC: { type: 'number', enum: [0, 1, 2], description: 'WebRTC: 0=replace, 1=real, 2=disable' },
334
- canvas: { type: 'boolean', description: 'Canvas: random vs real' },
335
- webGL: { type: 'boolean', description: 'WebGL: random vs real' },
336
- },
337
- },
338
- },
339
- required: ['workspaceId'],
340
- },
341
- },
342
- {
343
- name: 'roxy_create_browser_advanced',
344
- description: 'Create a browser with complete configuration control - for expert users needing full parameter access',
345
- inputSchema: {
346
- type: 'object',
347
- properties: {
348
- workspaceId: {
349
- type: 'number',
350
- description: 'Workspace ID (required)',
351
- },
352
- windowName: {
353
- type: 'string',
354
- description: 'Browser window name (optional)',
355
- },
356
- projectId: {
357
- type: 'number',
358
- description: 'Project ID (optional)',
359
- },
360
- windowRemark: {
361
- type: 'string',
362
- description: 'Window remarks/notes (optional)',
363
- },
364
- os: {
365
- type: 'string',
366
- enum: ['Windows', 'macOS', 'Linux', 'IOS', 'Android'],
367
- description: 'Operating system (optional)',
368
- },
369
- osVersion: {
370
- type: 'string',
371
- description: 'OS version (optional)',
372
- },
373
- coreVersion: {
374
- type: 'string',
375
- enum: ['140', '138', '137', '136', '135', '133', '130', '125', '117', '109'],
376
- description: 'Browser core version (optional)',
377
- },
378
- userAgent: {
379
- type: 'string',
380
- description: 'Custom user agent (optional)',
381
- },
382
- cookie: {
383
- type: 'array',
384
- items: {
385
- type: 'object',
386
- description: 'Cookie object (e.g., { name, value, domain, path, ... })',
387
- properties: {
388
- name: { type: 'string', description: 'Cookie name' },
389
- value: { type: 'string', description: 'Cookie value' },
390
- domain: { type: 'string', description: 'Cookie domain' },
391
- path: { type: 'string', description: 'Cookie path' },
392
- expires: { type: 'number', description: 'Expiration as UNIX timestamp (seconds)' },
393
- httpOnly: { type: 'boolean', description: 'HTTP-only cookie' },
394
- secure: { type: 'boolean', description: 'Secure cookie' },
395
- sameSite: { type: 'string', description: 'SameSite policy' },
396
- },
397
- additionalProperties: true,
398
- },
399
- description: 'Cookie list (optional)',
400
- },
401
- searchEngine: {
402
- type: 'string',
403
- enum: ['Google', 'Microsoft Bing', 'Yahoo', 'Yandex', 'DuckDuckGo'],
404
- description: 'Default search engine (optional)',
405
- },
406
- labelIds: {
407
- type: 'array',
408
- items: { type: 'number' },
409
- description: 'Label IDs to assign (optional)',
410
- },
411
- defaultOpenUrl: {
412
- type: 'array',
413
- items: { type: 'string' },
414
- description: 'Default URLs to open (optional)',
415
- },
416
- windowPlatformList: {
417
- type: 'array',
418
- items: {
419
- type: 'object',
420
- properties: {
421
- platformUrl: { type: 'string', description: 'Platform URL' },
422
- platformUserName: { type: 'string', description: 'Platform username' },
423
- platformPassword: { type: 'string', description: 'Platform password' },
424
- platformEfa: { type: 'string', description: 'Platform EFA' },
425
- platformRemarks: { type: 'string', description: 'Platform remarks' },
426
- },
427
- },
428
- description: 'Platform account information (optional)',
429
- },
430
- proxyInfo: {
431
- type: 'object',
432
- description: 'Complete proxy configuration (optional)',
433
- properties: {
434
- proxyMethod: { type: 'string', enum: ['custom', 'choose', 'api'] },
435
- proxyCategory: { type: 'string', enum: ['noproxy', 'HTTP', 'HTTPS', 'SOCKS5', 'SSH'] },
436
- ipType: { type: 'string', enum: ['IPV4', 'IPV6'] },
437
- protocol: { type: 'string', enum: ['HTTP', 'HTTPS', 'SOCKS5'] },
438
- host: { type: 'string' },
439
- port: { type: 'string' },
440
- proxyUserName: { type: 'string' },
441
- proxyPassword: { type: 'string' },
442
- refreshUrl: { type: 'string' },
443
- checkChannel: { type: 'string', enum: ['IPRust.io', 'IP-API', 'IP123.in'] },
444
- },
445
- },
446
- fingerInfo: {
447
- type: 'object',
448
- description: 'Complete fingerprint configuration (optional)',
449
- properties: {
450
- // Language and timezone
451
- isLanguageBaseIp: { type: 'boolean', description: 'Follow IP for browser language' },
452
- language: { type: 'string', description: 'Custom browser language' },
453
- isDisplayLanguageBaseIp: { type: 'boolean', description: 'Follow IP for display language' },
454
- displayLanguage: { type: 'string', description: 'Custom display language' },
455
- isTimeZone: { type: 'boolean', description: 'Follow IP for timezone' },
456
- timeZone: { type: 'string', description: 'Custom timezone' },
457
- // Geolocation
458
- position: { type: 'number', enum: [0, 1, 2], description: 'Geolocation prompt: 0=ask, 1=allow, 2=deny' },
459
- isPositionBaseIp: { type: 'boolean', description: 'Follow IP for geolocation' },
460
- longitude: { type: 'string', description: 'Custom longitude' },
461
- latitude: { type: 'string', description: 'Custom latitude' },
462
- precisionPos: { type: 'string', description: 'Precision in meters' },
463
- // Media settings
464
- forbidAudio: { type: 'boolean', description: 'Enable/disable sound' },
465
- forbidImage: { type: 'boolean', description: 'Enable/disable image loading' },
466
- forbidMedia: { type: 'boolean', description: 'Enable/disable video playback' },
467
- // Window settings
468
- openWidth: { type: 'string', description: 'Window width' },
469
- openHeight: { type: 'string', description: 'Window height' },
470
- openBookmarks: { type: 'boolean', description: 'Enable bookmarks' },
471
- positionSwitch: { type: 'boolean', description: 'Window position switch' },
472
- windowRatioPosition: { type: 'string', description: 'Window position ratio' },
473
- isDisplayName: { type: 'boolean', description: 'Show window name in title bar' },
474
- // Sync settings
475
- syncBookmark: { type: 'boolean', description: 'Sync bookmarks' },
476
- syncHistory: { type: 'boolean', description: 'Sync history' },
477
- syncTab: { type: 'boolean', description: 'Sync tabs' },
478
- syncCookie: { type: 'boolean', description: 'Sync cookies' },
479
- syncExtensions: { type: 'boolean', description: 'Sync extensions' },
480
- syncPassword: { type: 'boolean', description: 'Sync saved passwords' },
481
- syncIndexedDb: { type: 'boolean', description: 'Sync IndexedDB' },
482
- syncLocalStorage: { type: 'boolean', description: 'Sync LocalStorage' },
483
- // Cleanup settings
484
- clearCacheFile: { type: 'boolean', description: 'Clear cache files on startup' },
485
- clearCookie: { type: 'boolean', description: 'Clear cookies on startup' },
486
- clearLocalStorage: { type: 'boolean', description: 'Clear LocalStorage on startup' },
487
- // Advanced settings
488
- randomFingerprint: { type: 'boolean', description: 'Generate random fingerprint' },
489
- forbidSavePassword: { type: 'boolean', description: 'Disable password save prompts' },
490
- stopOpenNet: { type: 'boolean', description: 'Stop opening if network fails' },
491
- stopOpenIP: { type: 'boolean', description: 'Stop opening if IP changes' },
492
- stopOpenPosition: { type: 'boolean', description: 'Stop opening if IP location changes' },
493
- openWorkbench: { type: 'number', enum: [0, 1, 2], description: 'Open workbench: 0=close, 1=open, 2=follow app' },
494
- // Display settings
495
- resolutionType: { type: 'boolean', description: 'Custom resolution vs follow system' },
496
- resolutionX: { type: 'string', description: 'Custom resolution width' },
497
- resolutionY: { type: 'string', description: 'Custom resolution height' },
498
- fontType: { type: 'boolean', description: 'Random fonts vs system fonts' },
499
- // Browser fingerprint settings
500
- webRTC: { type: 'number', enum: [0, 1, 2], description: 'WebRTC: 0=replace, 1=real, 2=disable' },
501
- webGL: { type: 'boolean', description: 'WebGL: random vs real' },
502
- webGLInfo: { type: 'boolean', description: 'WebGL info: custom vs real' },
503
- webGLManufacturer: { type: 'string', description: 'Custom WebGL manufacturer' },
504
- webGLRender: { type: 'string', description: 'Custom WebGL renderer' },
505
- webGpu: { type: 'string', enum: ['webgl', 'real', 'block'], description: 'WebGPU setting' },
506
- canvas: { type: 'boolean', description: 'Canvas: random vs real' },
507
- audioContext: { type: 'boolean', description: 'AudioContext: random vs real' },
508
- speechVoices: { type: 'boolean', description: 'Speech Voices: random vs real' },
509
- doNotTrack: { type: 'boolean', description: 'Enable Do Not Track' },
510
- clientRects: { type: 'boolean', description: 'ClientRects: random vs real' },
511
- deviceInfo: { type: 'boolean', description: 'Media devices: random vs real' },
512
- deviceNameSwitch: { type: 'boolean', description: 'Device names: random vs real' },
513
- macInfo: { type: 'boolean', description: 'MAC address: custom vs real' },
514
- // Hardware settings
515
- hardwareConcurrent: { type: 'string', description: 'Hardware concurrency' },
516
- deviceMemory: { type: 'string', description: 'Device memory' },
517
- // Security settings
518
- disableSsl: { type: 'boolean', description: 'SSL fingerprint settings' },
519
- disableSslList: { type: 'array', items: { type: 'string' }, description: 'SSL feature list' },
520
- portScanProtect: { type: 'boolean', description: 'Port scan protection' },
521
- portScanList: { type: 'string', description: 'Port scan whitelist' },
522
- useGpu: { type: 'boolean', description: 'Use GPU acceleration' },
523
- sandboxPermission: { type: 'boolean', description: 'Disable sandbox' },
524
- startupParam: { type: 'string', description: 'Browser startup parameters' },
525
- },
526
- },
527
- },
528
- required: ['workspaceId'],
529
- },
530
- },
531
- {
532
- name: 'roxy_validate_proxy_config',
533
- description: 'Validate proxy configuration before using it',
534
- inputSchema: {
535
- type: 'object',
536
- properties: {
537
- proxyInfo: {
538
- type: 'object',
539
- description: 'Proxy configuration to validate (required)',
540
- properties: {
541
- proxyMethod: { type: 'string', enum: ['custom', 'choose', 'api'] },
542
- proxyCategory: { type: 'string', enum: ['noproxy', 'HTTP', 'HTTPS', 'SOCKS5', 'SSH'] },
543
- ipType: { type: 'string', enum: ['IPV4', 'IPV6'] },
544
- protocol: { type: 'string', enum: ['HTTP', 'HTTPS', 'SOCKS5'] },
545
- host: { type: 'string' },
546
- port: { type: 'string' },
547
- proxyUserName: { type: 'string' },
548
- proxyPassword: { type: 'string' },
549
- refreshUrl: { type: 'string' },
550
- checkChannel: { type: 'string', enum: ['IPRust.io', 'IP-API', 'IP123.in'] },
551
- },
552
- },
553
- },
554
- required: ['proxyInfo'],
555
- },
556
- },
557
- {
558
- name: 'roxy_system_diagnostics',
559
- description: 'Perform comprehensive system diagnostics and health checks',
560
- inputSchema: {
561
- type: 'object',
562
- properties: {
563
- includeWorkspaceCheck: {
564
- type: 'boolean',
565
- description: 'Include workspace connectivity tests (optional, default: true)',
566
- default: true,
567
- },
568
- includeBrowserCheck: {
569
- type: 'boolean',
570
- description: 'Include browser availability checks (optional, default: true)',
571
- default: true,
572
- },
573
- verbose: {
574
- type: 'boolean',
575
- description: 'Include detailed diagnostic information (optional, default: false)',
576
- default: false,
577
- },
578
- },
579
- },
580
- },
581
- {
582
- name: 'roxy_list_accounts',
583
- description: 'Get list of accounts (platform credentials) in specified workspace',
584
- inputSchema: {
585
- type: 'object',
586
- properties: {
587
- workspaceId: {
588
- type: 'number',
589
- description: 'Workspace ID (required)',
590
- },
591
- accountId: {
592
- type: 'number',
593
- description: 'Account ID to filter by (optional)',
594
- },
595
- pageIndex: {
596
- type: 'number',
597
- description: 'Page index for pagination (default: 1)',
598
- default: 1,
599
- },
600
- pageSize: {
601
- type: 'number',
602
- description: 'Number of items per page (default: 15)',
603
- default: 15,
604
- },
605
- },
606
- required: ['workspaceId'],
607
- },
608
- },
609
- {
610
- name: 'roxy_list_labels',
611
- description: 'Get list of labels in specified workspace',
612
- inputSchema: {
613
- type: 'object',
614
- properties: {
615
- workspaceId: {
616
- type: 'number',
617
- description: 'Workspace ID (required)',
618
- },
619
- },
620
- required: ['workspaceId'],
621
- },
622
- },
623
- {
624
- name: 'roxy_get_connection_info',
625
- description: 'Get connection information (CDP endpoints, PIDs) for currently opened browsers',
626
- inputSchema: {
627
- type: 'object',
628
- properties: {
629
- dirIds: {
630
- type: 'array',
631
- items: { type: 'string' },
632
- description: 'Array of browser directory IDs to query (optional, returns all if not specified)',
633
- },
634
- },
635
- },
636
- },
637
- {
638
- name: 'roxy_get_browser_detail',
639
- description: 'Get detailed information for a specific browser window',
640
- inputSchema: {
641
- type: 'object',
642
- properties: {
643
- workspaceId: {
644
- type: 'number',
645
- description: 'Workspace ID (required)',
646
- },
647
- dirId: {
648
- type: 'string',
649
- description: 'Browser directory ID (required)',
650
- },
651
- },
652
- required: ['workspaceId', 'dirId'],
653
- },
654
- },
655
- {
656
- name: 'roxy_update_browser',
657
- description: 'Update/modify an existing browser configuration with full control over all settings',
658
- inputSchema: {
659
- type: 'object',
660
- properties: {
661
- workspaceId: {
662
- type: 'number',
663
- description: 'Workspace ID (required)',
664
- },
665
- dirId: {
666
- type: 'string',
667
- description: 'Browser directory ID to update (required)',
668
- },
669
- windowName: {
670
- type: 'string',
671
- description: 'Browser window name (optional)',
672
- },
673
- projectId: {
674
- type: 'number',
675
- description: 'Project ID (optional)',
676
- },
677
- windowRemark: {
678
- type: 'string',
679
- description: 'Window remarks/notes (optional)',
680
- },
681
- os: {
682
- type: 'string',
683
- enum: ['Windows', 'macOS', 'Linux', 'IOS', 'Android'],
684
- description: 'Operating system (optional)',
685
- },
686
- osVersion: {
687
- type: 'string',
688
- description: 'OS version (optional)',
689
- },
690
- coreVersion: {
691
- type: 'string',
692
- enum: ['140', '138', '137', '136', '135', '133', '130', '125', '117', '109'],
693
- description: 'Browser core version (optional)',
694
- },
695
- userAgent: {
696
- type: 'string',
697
- description: 'Custom user agent (optional)',
698
- },
699
- cookie: {
700
- type: 'array',
701
- items: {
702
- type: 'object',
703
- description: 'Cookie object (e.g., { name, value, domain, path, ... })',
704
- properties: {
705
- name: { type: 'string', description: 'Cookie name' },
706
- value: { type: 'string', description: 'Cookie value' },
707
- domain: { type: 'string', description: 'Cookie domain' },
708
- path: { type: 'string', description: 'Cookie path' },
709
- expires: { type: 'number', description: 'Expiration as UNIX timestamp (seconds)' },
710
- httpOnly: { type: 'boolean', description: 'HTTP-only cookie' },
711
- secure: { type: 'boolean', description: 'Secure cookie' },
712
- sameSite: { type: 'string', description: 'SameSite policy' },
713
- },
714
- additionalProperties: true,
715
- },
716
- description: 'Cookie list (optional)',
717
- },
718
- searchEngine: {
719
- type: 'string',
720
- enum: ['Google', 'Microsoft Bing', 'Yahoo', 'Yandex', 'DuckDuckGo'],
721
- description: 'Default search engine (optional)',
722
- },
723
- labelIds: {
724
- type: 'array',
725
- items: { type: 'number' },
726
- description: 'Label IDs to assign (optional)',
727
- },
728
- defaultOpenUrl: {
729
- type: 'array',
730
- items: { type: 'string' },
731
- description: 'Default URLs to open (optional)',
732
- },
733
- windowPlatformList: {
734
- type: 'array',
735
- items: {
736
- type: 'object',
737
- properties: {
738
- platformUrl: { type: 'string', description: 'Platform URL' },
739
- platformUserName: { type: 'string', description: 'Platform username' },
740
- platformPassword: { type: 'string', description: 'Platform password' },
741
- platformEfa: { type: 'string', description: 'Platform EFA' },
742
- platformRemarks: { type: 'string', description: 'Platform remarks' },
743
- },
744
- },
745
- description: 'Platform account information (optional)',
746
- },
747
- proxyInfo: {
748
- type: 'object',
749
- description: 'Complete proxy configuration (optional)',
750
- properties: {
751
- proxyMethod: { type: 'string', enum: ['custom', 'choose', 'api'] },
752
- proxyCategory: { type: 'string', enum: ['noproxy', 'HTTP', 'HTTPS', 'SOCKS5', 'SSH'] },
753
- ipType: { type: 'string', enum: ['IPV4', 'IPV6'] },
754
- protocol: { type: 'string', enum: ['HTTP', 'HTTPS', 'SOCKS5'] },
755
- host: { type: 'string' },
756
- port: { type: 'string' },
757
- proxyUserName: { type: 'string' },
758
- proxyPassword: { type: 'string' },
759
- refreshUrl: { type: 'string' },
760
- checkChannel: { type: 'string', enum: ['IPRust.io', 'IP-API', 'IP123.in'] },
761
- },
762
- },
763
- fingerInfo: {
764
- type: 'object',
765
- description: 'Complete fingerprint configuration (optional)',
766
- properties: {
767
- // Language and timezone
768
- isLanguageBaseIp: { type: 'boolean', description: 'Follow IP for browser language' },
769
- language: { type: 'string', description: 'Custom browser language' },
770
- isDisplayLanguageBaseIp: { type: 'boolean', description: 'Follow IP for display language' },
771
- displayLanguage: { type: 'string', description: 'Custom display language' },
772
- isTimeZone: { type: 'boolean', description: 'Follow IP for timezone' },
773
- timeZone: { type: 'string', description: 'Custom timezone' },
774
- // Geolocation
775
- position: { type: 'number', enum: [0, 1, 2], description: 'Geolocation prompt: 0=ask, 1=allow, 2=deny' },
776
- isPositionBaseIp: { type: 'boolean', description: 'Follow IP for geolocation' },
777
- longitude: { type: 'string', description: 'Custom longitude' },
778
- latitude: { type: 'string', description: 'Custom latitude' },
779
- precisionPos: { type: 'string', description: 'Precision in meters' },
780
- // Media settings
781
- forbidAudio: { type: 'boolean', description: 'Enable/disable sound' },
782
- forbidImage: { type: 'boolean', description: 'Enable/disable image loading' },
783
- forbidMedia: { type: 'boolean', description: 'Enable/disable video playback' },
784
- // Window settings
785
- openWidth: { type: 'string', description: 'Window width' },
786
- openHeight: { type: 'string', description: 'Window height' },
787
- openBookmarks: { type: 'boolean', description: 'Enable bookmarks' },
788
- positionSwitch: { type: 'boolean', description: 'Window position switch' },
789
- windowRatioPosition: { type: 'string', description: 'Window position ratio' },
790
- isDisplayName: { type: 'boolean', description: 'Show window name in title bar' },
791
- // Sync settings
792
- syncBookmark: { type: 'boolean', description: 'Sync bookmarks' },
793
- syncHistory: { type: 'boolean', description: 'Sync history' },
794
- syncTab: { type: 'boolean', description: 'Sync tabs' },
795
- syncCookie: { type: 'boolean', description: 'Sync cookies' },
796
- syncExtensions: { type: 'boolean', description: 'Sync extensions' },
797
- syncPassword: { type: 'boolean', description: 'Sync saved passwords' },
798
- syncIndexedDb: { type: 'boolean', description: 'Sync IndexedDB' },
799
- syncLocalStorage: { type: 'boolean', description: 'Sync LocalStorage' },
800
- // Cleanup settings
801
- clearCacheFile: { type: 'boolean', description: 'Clear cache files on startup' },
802
- clearCookie: { type: 'boolean', description: 'Clear cookies on startup' },
803
- clearLocalStorage: { type: 'boolean', description: 'Clear LocalStorage on startup' },
804
- // Advanced settings
805
- randomFingerprint: { type: 'boolean', description: 'Generate random fingerprint' },
806
- forbidSavePassword: { type: 'boolean', description: 'Disable password save prompts' },
807
- stopOpenNet: { type: 'boolean', description: 'Stop opening if network fails' },
808
- stopOpenIP: { type: 'boolean', description: 'Stop opening if IP changes' },
809
- stopOpenPosition: { type: 'boolean', description: 'Stop opening if IP location changes' },
810
- openWorkbench: { type: 'number', enum: [0, 1, 2], description: 'Open workbench: 0=close, 1=open, 2=follow app' },
811
- // Display settings
812
- resolutionType: { type: 'boolean', description: 'Custom resolution vs follow system' },
813
- resolutionX: { type: 'string', description: 'Custom resolution width' },
814
- resolutionY: { type: 'string', description: 'Custom resolution height' },
815
- fontType: { type: 'boolean', description: 'Random fonts vs system fonts' },
816
- // Browser fingerprint settings
817
- webRTC: { type: 'number', enum: [0, 1, 2], description: 'WebRTC: 0=replace, 1=real, 2=disable' },
818
- webGL: { type: 'boolean', description: 'WebGL: random vs real' },
819
- webGLInfo: { type: 'boolean', description: 'WebGL info: custom vs real' },
820
- webGLManufacturer: { type: 'string', description: 'Custom WebGL manufacturer' },
821
- webGLRender: { type: 'string', description: 'Custom WebGL renderer' },
822
- webGpu: { type: 'string', enum: ['webgl', 'real', 'block'], description: 'WebGPU setting' },
823
- canvas: { type: 'boolean', description: 'Canvas: random vs real' },
824
- audioContext: { type: 'boolean', description: 'AudioContext: random vs real' },
825
- speechVoices: { type: 'boolean', description: 'Speech Voices: random vs real' },
826
- doNotTrack: { type: 'boolean', description: 'Enable Do Not Track' },
827
- clientRects: { type: 'boolean', description: 'ClientRects: random vs real' },
828
- deviceInfo: { type: 'boolean', description: 'Media devices: random vs real' },
829
- deviceNameSwitch: { type: 'boolean', description: 'Device names: random vs real' },
830
- macInfo: { type: 'boolean', description: 'MAC address: custom vs real' },
831
- // Hardware settings
832
- hardwareConcurrent: { type: 'string', description: 'Hardware concurrency' },
833
- deviceMemory: { type: 'string', description: 'Device memory' },
834
- // Security settings
835
- disableSsl: { type: 'boolean', description: 'SSL fingerprint settings' },
836
- disableSslList: { type: 'array', items: { type: 'string' }, description: 'SSL feature list' },
837
- portScanProtect: { type: 'boolean', description: 'Port scan protection' },
838
- portScanList: { type: 'string', description: 'Port scan whitelist' },
839
- useGpu: { type: 'boolean', description: 'Use GPU acceleration' },
840
- sandboxPermission: { type: 'boolean', description: 'Disable sandbox' },
841
- startupParam: { type: 'string', description: 'Browser startup parameters' },
842
- },
843
- },
844
- },
845
- required: ['workspaceId', 'dirId'],
846
- },
847
- },
848
- {
849
- name: 'roxy_random_fingerprint',
850
- description: 'Randomize browser fingerprint for a specific browser',
851
- inputSchema: {
852
- type: 'object',
853
- properties: {
854
- workspaceId: {
855
- type: 'number',
856
- description: 'Workspace ID (required)',
857
- },
858
- dirId: {
859
- type: 'string',
860
- description: 'Browser directory ID (required)',
861
- },
862
- },
863
- required: ['workspaceId', 'dirId'],
864
- },
865
- },
866
- {
867
- name: 'roxy_clear_local_cache',
868
- description: 'Clear local cache for specified browsers',
869
- inputSchema: {
870
- type: 'object',
871
- properties: {
872
- dirIds: {
873
- type: 'array',
874
- items: { type: 'string' },
875
- description: 'Array of browser directory IDs (required)',
876
- },
877
- },
878
- required: ['dirIds'],
879
- },
880
- },
881
- {
882
- name: 'roxy_clear_server_cache',
883
- description: 'Clear server-side cache for specified browsers',
884
- inputSchema: {
885
- type: 'object',
886
- properties: {
887
- workspaceId: {
888
- type: 'number',
889
- description: 'Workspace ID (required)',
890
- },
891
- dirIds: {
892
- type: 'array',
893
- items: { type: 'string' },
894
- description: 'Array of browser directory IDs (required)',
895
- },
896
- },
897
- required: ['workspaceId', 'dirIds'],
898
- },
899
- },
18
+ listBrowsers.schema,
19
+ batchCreateBrowsers.schema,
20
+ createBrowser.schema,
21
+ openBrowser.schema,
22
+ updateBrowser.schema,
23
+ closeBrowsers.schema,
24
+ deleteBrowsers.schema,
25
+ getBrowserDetail.schema,
26
+ clearLocalCache.schema,
27
+ clearServerCache.schema,
28
+ randomFingerprint.schema,
29
+ listLabels.schema,
30
+ getConnectionInfo.schema,
31
+ proxyList.schema,
32
+ proxyStore.schema,
33
+ createProxy.schema,
34
+ batchCreateProxies.schema,
35
+ detectProxy.schema,
36
+ modifyProxy.schema,
37
+ deleteProxies.schema,
38
+ // getDetectChannels.schema,
39
+ listAccounts.schema,
40
+ createAccount.schema,
41
+ batchCreateAccounts.schema,
42
+ modifyAccount.schema,
43
+ deleteAccounts.schema,
44
+ listWorkspaces.schema,
45
+ healthCheck.schema,
900
46
  ];
901
47
  // ========== MCP Server ==========
902
48
  class RoxyBrowserMCPServer {
903
49
  server;
904
- roxyClient;
905
50
  constructor() {
906
51
  this.server = new Server({
907
- name: 'roxy-browser-mcp',
52
+ name: 'roxybrowser-openapi-mcp',
908
53
  version: '1.0.0',
909
54
  }, {
910
55
  capabilities: {
911
56
  tools: {},
912
57
  },
913
58
  });
914
- // Initialize RoxyBrowser client
915
- const config = getConfig();
916
- this.roxyClient = new RoxyClient(config);
917
59
  this.setupHandlers();
60
+ // Initialize RoxyBrowser client
61
+ // const config = getConfig()
62
+ // this.roxyClient = new RoxyClient(config)
918
63
  }
919
64
  setupHandlers() {
920
65
  // List available tools
@@ -926,804 +71,82 @@ class RoxyBrowserMCPServer {
926
71
  const { name, arguments: args } = request.params;
927
72
  try {
928
73
  switch (name) {
929
- case 'roxy_list_workspaces':
930
- return await this.handleListWorkspaces(args);
931
- case 'roxy_list_browsers':
932
- return await this.handleListBrowsers(args);
933
- case 'roxy_open_browsers':
934
- return await this.handleOpenBrowsers(args);
935
- case 'roxy_close_browsers':
936
- return await this.handleCloseBrowsers(args);
937
- case 'roxy_delete_browsers':
938
- return await this.handleDeleteBrowsers(args);
939
- case 'roxy_create_browser_simple':
940
- return await this.handleCreateBrowserSimple(args);
941
- case 'roxy_create_browser_standard':
942
- return await this.handleCreateBrowserStandard(args);
943
- case 'roxy_create_browser_advanced':
944
- return await this.handleCreateBrowserAdvanced(args);
945
- case 'roxy_validate_proxy_config':
946
- return await this.handleValidateProxyConfig(args);
947
- case 'roxy_system_diagnostics':
948
- return await this.handleSystemDiagnostics(args);
949
- case 'roxy_list_accounts':
950
- return await this.handleListAccounts(args);
951
- case 'roxy_list_labels':
952
- return await this.handleListLabels(args);
953
- case 'roxy_get_connection_info':
954
- return await this.handleGetConnectionInfo(args);
955
- case 'roxy_get_browser_detail':
956
- return await this.handleGetBrowserDetail(args);
957
- case 'roxy_update_browser':
958
- return await this.handleUpdateBrowser(args);
959
- case 'roxy_random_fingerprint':
960
- return await this.handleRandomFingerprint(args);
961
- case 'roxy_clear_local_cache':
962
- return await this.handleClearLocalCache(args);
963
- case 'roxy_clear_server_cache':
964
- return await this.handleClearServerCache(args);
74
+ // 浏览器相关
75
+ case listBrowsers.name:
76
+ return await listBrowsers.handle(args);
77
+ case createBrowser.name:
78
+ return await createBrowser.handle(args);
79
+ case openBrowser.name:
80
+ return await openBrowser.handle(args);
81
+ case updateBrowser.name:
82
+ return await updateBrowser.handle(args);
83
+ case closeBrowsers.name:
84
+ return await closeBrowsers.handle(args);
85
+ case deleteBrowsers.name:
86
+ return await deleteBrowsers.handle(args);
87
+ case batchCreateBrowsers.name:
88
+ return await batchCreateBrowsers.handle(args);
89
+ case listLabels.name:
90
+ return await listLabels.handle(args);
91
+ case getConnectionInfo.name:
92
+ return await getConnectionInfo.handle(args);
93
+ case randomFingerprint.name:
94
+ return await randomFingerprint.handle(args);
95
+ case clearLocalCache.name:
96
+ return await clearLocalCache.handle(args);
97
+ case clearServerCache.name:
98
+ return await clearServerCache.handle(args);
99
+ case getBrowserDetail.name:
100
+ return await getBrowserDetail.handle(args);
101
+ // 账号相关
102
+ case listAccounts.name:
103
+ return await listAccounts.handle(args);
104
+ case createAccount.name:
105
+ return await createAccount.handle(args);
106
+ case batchCreateAccounts.name:
107
+ return await batchCreateAccounts.handle(args);
108
+ case modifyAccount.name:
109
+ return await modifyAccount.handle(args);
110
+ case deleteAccounts.name:
111
+ return await deleteAccounts.handle(args);
112
+ // 代理相关
113
+ case proxyList.name:
114
+ return await proxyList.handle(args);
115
+ case proxyStore.name:
116
+ return await proxyStore.handle(args);
117
+ case createProxy.name:
118
+ return await createProxy.handle(args);
119
+ case batchCreateProxies.name:
120
+ return await batchCreateProxies.handle(args);
121
+ case detectProxy.name:
122
+ return await detectProxy.handle(args);
123
+ case modifyProxy.name:
124
+ return await modifyProxy.handle(args);
125
+ case deleteProxies.name:
126
+ return await deleteProxies.handle(args);
127
+ // 空间列表
128
+ case listWorkspaces.name:
129
+ return await listWorkspaces.handle(args);
130
+ // 健康检查
131
+ case healthCheck.name:
132
+ return await healthCheck.handle(args);
965
133
  default:
966
134
  throw new Error(`Unknown tool: ${name}`);
967
135
  }
968
136
  }
969
137
  catch (error) {
970
- // Use enhanced error analysis
971
- const formattedError = ErrorAnalyzer.formatErrorForDisplay(error instanceof Error ? error : new Error('Unknown error'));
972
138
  return {
973
139
  content: [
974
140
  {
975
141
  type: 'text',
976
- text: formattedError,
142
+ text: error instanceof Error ? error.message : 'Unknown error',
977
143
  },
978
144
  ],
979
145
  };
980
146
  }
981
147
  });
982
148
  }
983
- async handleCreateBrowserSimple(args) {
984
- const params = args;
985
- if (!params.workspaceId) {
986
- throw new Error('workspaceId is required');
987
- }
988
- try {
989
- // Build configuration from simple parameters
990
- const config = BrowserCreator.buildSimpleConfig(params);
991
- const finalConfig = BrowserCreator.applyDefaults(config);
992
- // Validate configuration
993
- const validation = BrowserCreator.validateConfig(finalConfig);
994
- if (!validation.valid) {
995
- throw new BrowserCreationError(`Configuration validation failed: ${validation.errors.join(', ')}`);
996
- }
997
- // Create browser
998
- const result = await this.roxyClient.createBrowser(finalConfig);
999
- const response = {
1000
- browser: {
1001
- dirId: result.dirId,
1002
- windowName: finalConfig.windowName || 'Simple Browser',
1003
- workspaceId: params.workspaceId,
1004
- projectId: params.projectId,
1005
- proxyConfigured: !!(params.proxyHost && params.proxyPort),
1006
- },
1007
- message: `Browser created successfully with ID: ${result.dirId}`,
1008
- };
1009
- return {
1010
- content: [
1011
- {
1012
- type: 'text',
1013
- text: `✅ **Simple Browser Created**\n\n` +
1014
- `**Browser ID:** \`${response.browser.dirId}\`\n` +
1015
- `**Name:** ${response.browser.windowName}\n` +
1016
- `**Workspace:** ${response.browser.workspaceId}\n` +
1017
- `${response.browser.projectId ? `**Project:** ${response.browser.projectId}\n` : ''}` +
1018
- `**Proxy:** ${response.browser.proxyConfigured ? '✅ Configured' : '❌ Not configured'}\n\n` +
1019
- `*Use this browser ID with \`roxy_open_browsers\` to start the browser and get CDP endpoints for automation.*`,
1020
- },
1021
- ],
1022
- };
1023
- }
1024
- catch (error) {
1025
- // Check for quota error specifically
1026
- if (error instanceof RoxyApiError && error.code === 409 &&
1027
- error.message.includes('额度不足')) {
1028
- return {
1029
- content: [{
1030
- type: 'text',
1031
- text: `❌ **浏览器创建失败 - 窗口额度不足 / Browser Creation Failed - Insufficient Profiles Quota**\n\n` +
1032
- `**错误信息 / Error:** ${error.message}\n\n` +
1033
- `**解决步骤 / Solution Steps:**\n` +
1034
- `1. 打开 RoxyBrowser 应用 / Open RoxyBrowser app\n` +
1035
- `2. 前往费用中心 / Go to Billing Center\n` +
1036
- `3. 购买或升级窗口套餐 / Purchase or upgrade profiles plan\n` +
1037
- `4. 或者删除不需要的浏览器窗口以释放额度 / Or delete unused browser profiles to free up quota\n` +
1038
- `5. 等待生效后重试创建 / Retry creation after quota is available\n\n` +
1039
- `💡 **重要提示 / Important:** 必须使用 \`roxy_delete_browsers\` 删除浏览器才能释放额度,仅关闭浏览器无法释放额度。\n` +
1040
- `You must use \`roxy_delete_browsers\` to delete profiles to free up quota. Simply closing browsers will NOT free up quota.`,
1041
- }],
1042
- };
1043
- }
1044
- // Use enhanced error analysis for other errors
1045
- const formattedError = ErrorAnalyzer.formatErrorForDisplay(error instanceof Error ? error : new Error('Unknown error'));
1046
- return {
1047
- content: [{ type: 'text', text: formattedError }],
1048
- };
1049
- }
1050
- }
1051
- async handleCreateBrowserStandard(args) {
1052
- const params = args;
1053
- if (!params.workspaceId) {
1054
- throw new Error('workspaceId is required');
1055
- }
1056
- try {
1057
- // Build configuration from standard parameters
1058
- const config = BrowserCreator.buildStandardConfig(params);
1059
- const finalConfig = BrowserCreator.applyDefaults(config);
1060
- // Validate configuration
1061
- const validation = BrowserCreator.validateConfig(finalConfig);
1062
- if (!validation.valid) {
1063
- throw new BrowserCreationError(`Configuration validation failed: ${validation.errors.join(', ')}`);
1064
- }
1065
- // Create browser
1066
- const result = await this.roxyClient.createBrowser(finalConfig);
1067
- const response = {
1068
- browser: {
1069
- dirId: result.dirId,
1070
- windowName: finalConfig.windowName || 'Standard Browser',
1071
- workspaceId: params.workspaceId,
1072
- projectId: params.projectId,
1073
- os: finalConfig.os || 'Windows',
1074
- coreVersion: finalConfig.coreVersion || LATEST_CORE_VERSION,
1075
- proxyInfo: params.proxyInfo,
1076
- windowSize: `${params.openWidth || '1000'}x${params.openHeight || '1000'}`,
1077
- },
1078
- message: `Standard browser created successfully with ID: ${result.dirId}`,
1079
- };
1080
- return {
1081
- content: [
1082
- {
1083
- type: 'text',
1084
- text: `✅ **Standard Browser Created**\n\n` +
1085
- `**Browser ID:** \`${response.browser.dirId}\`\n` +
1086
- `**Name:** ${response.browser.windowName}\n` +
1087
- `**OS:** ${response.browser.os} ${finalConfig.osVersion || ''}\n` +
1088
- `**Core Version:** ${response.browser.coreVersion}\n` +
1089
- `**Window Size:** ${response.browser.windowSize}\n` +
1090
- `**Workspace:** ${response.browser.workspaceId}\n` +
1091
- `${response.browser.projectId ? `**Project:** ${response.browser.projectId}\n` : ''}` +
1092
- `**Proxy:** ${response.browser.proxyInfo ? '✅ Configured' : '❌ Not configured'}\n\n` +
1093
- `*Browser is ready for automation. Use \`roxy_open_browsers\` to start it.*`,
1094
- },
1095
- ],
1096
- };
1097
- }
1098
- catch (error) {
1099
- // Check for quota error specifically
1100
- if (error instanceof RoxyApiError && error.code === 409 &&
1101
- error.message.includes('额度不足')) {
1102
- return {
1103
- content: [{
1104
- type: 'text',
1105
- text: `❌ **浏览器创建失败 - 窗口额度不足 / Browser Creation Failed - Insufficient Profiles Quota**\n\n` +
1106
- `**错误信息 / Error:** ${error.message}\n\n` +
1107
- `**解决步骤 / Solution Steps:**\n` +
1108
- `1. 打开 RoxyBrowser 应用 / Open RoxyBrowser app\n` +
1109
- `2. 前往费用中心 / Go to Billing Center\n` +
1110
- `3. 购买或升级窗口套餐 / Purchase or upgrade profiles plan\n` +
1111
- `4. 或者删除不需要的浏览器窗口以释放额度 / Or delete unused browser profiles to free up quota\n` +
1112
- `5. 等待生效后重试创建 / Retry creation after quota is available\n\n` +
1113
- `💡 **重要提示 / Important:** 必须使用 \`roxy_delete_browsers\` 删除浏览器才能释放额度,仅关闭浏览器无法释放额度。\n` +
1114
- `You must use \`roxy_delete_browsers\` to delete profiles to free up quota. Simply closing browsers will NOT free up quota.`,
1115
- }],
1116
- };
1117
- }
1118
- // Use enhanced error analysis for other errors
1119
- const formattedError = ErrorAnalyzer.formatErrorForDisplay(error instanceof Error ? error : new Error('Unknown error'));
1120
- return {
1121
- content: [{ type: 'text', text: formattedError }],
1122
- };
1123
- }
1124
- }
1125
- async handleCreateBrowserAdvanced(args) {
1126
- const params = args;
1127
- if (!params.workspaceId) {
1128
- throw new Error('workspaceId is required');
1129
- }
1130
- try {
1131
- // Build configuration from advanced parameters
1132
- const config = BrowserCreator.buildAdvancedConfig(params);
1133
- const finalConfig = BrowserCreator.applyDefaults(config);
1134
- // Validate configuration
1135
- const validation = BrowserCreator.validateConfig(finalConfig);
1136
- if (!validation.valid) {
1137
- throw new BrowserCreationError(`Configuration validation failed: ${validation.errors.join(', ')}`);
1138
- }
1139
- // Create browser
1140
- const result = await this.roxyClient.createBrowser(finalConfig);
1141
- const response = {
1142
- browser: {
1143
- dirId: result.dirId,
1144
- config: finalConfig,
1145
- },
1146
- message: `Advanced browser created successfully with ID: ${result.dirId}`,
1147
- };
1148
- // Create detailed status text
1149
- const configSummary = [
1150
- `**Browser ID:** \`${response.browser.dirId}\``,
1151
- `**Name:** ${finalConfig.windowName || 'Advanced Browser'}`,
1152
- `**OS:** ${finalConfig.os || 'Windows'} ${finalConfig.osVersion || ''}`,
1153
- `**Core Version:** ${finalConfig.coreVersion || LATEST_CORE_VERSION}`,
1154
- finalConfig.userAgent ? `**User Agent:** ${finalConfig.userAgent.substring(0, 50)}...` : '',
1155
- `**Search Engine:** ${finalConfig.searchEngine || 'Google'}`,
1156
- finalConfig.proxyInfo?.proxyCategory !== 'noproxy' ? `**Proxy:** ✅ ${finalConfig.proxyInfo?.proxyCategory} ${finalConfig.proxyInfo?.host}:${finalConfig.proxyInfo?.port}` : '**Proxy:** ❌ No proxy',
1157
- finalConfig.fingerInfo?.randomFingerprint ? '**Fingerprint:** 🎲 Random' : '**Fingerprint:** 🔒 Fixed',
1158
- finalConfig.defaultOpenUrl?.length ? `**Default URLs:** ${finalConfig.defaultOpenUrl.length} URL(s)` : '',
1159
- ].filter(Boolean).join('\n');
1160
- return {
1161
- content: [
1162
- {
1163
- type: 'text',
1164
- text: `✅ **Advanced Browser Created**\n\n${configSummary}\n\n` +
1165
- `*Advanced browser configured with complete control. Use \`roxy_open_browsers\` to start it.*`,
1166
- },
1167
- ],
1168
- };
1169
- }
1170
- catch (error) {
1171
- // Check for quota error specifically
1172
- if (error instanceof RoxyApiError && error.code === 409 &&
1173
- error.message.includes('额度不足')) {
1174
- return {
1175
- content: [{
1176
- type: 'text',
1177
- text: `❌ **浏览器创建失败 - 窗口额度不足 / Browser Creation Failed - Insufficient Profiles Quota**\n\n` +
1178
- `**错误信息 / Error:** ${error.message}\n\n` +
1179
- `**解决步骤 / Solution Steps:**\n` +
1180
- `1. 打开 RoxyBrowser 应用 / Open RoxyBrowser app\n` +
1181
- `2. 前往费用中心 / Go to Billing Center\n` +
1182
- `3. 购买或升级窗口套餐 / Purchase or upgrade profiles plan\n` +
1183
- `4. 或者删除不需要的浏览器窗口以释放额度 / Or delete unused browser profiles to free up quota\n` +
1184
- `5. 等待生效后重试创建 / Retry creation after quota is available\n\n` +
1185
- `💡 **重要提示 / Important:** 必须使用 \`roxy_delete_browsers\` 删除浏览器才能释放额度,仅关闭浏览器无法释放额度。\n` +
1186
- `You must use \`roxy_delete_browsers\` to delete profiles to free up quota. Simply closing browsers will NOT free up quota.`,
1187
- }],
1188
- };
1189
- }
1190
- // Use enhanced error analysis for other errors
1191
- const formattedError = ErrorAnalyzer.formatErrorForDisplay(error instanceof Error ? error : new Error('Unknown error'));
1192
- return {
1193
- content: [{ type: 'text', text: formattedError }],
1194
- };
1195
- }
1196
- }
1197
- async handleValidateProxyConfig(args) {
1198
- const { proxyInfo } = args;
1199
- if (!proxyInfo) {
1200
- throw new Error('proxyInfo is required');
1201
- }
1202
- const validation = ProxyManager.validateProxy(proxyInfo);
1203
- let resultText = '';
1204
- if (validation.valid) {
1205
- resultText = `✅ **Proxy Configuration Valid**\n\n` +
1206
- `**Type:** ${proxyInfo.proxyCategory || 'Not specified'}\n` +
1207
- `**Host:** ${proxyInfo.host || 'Not specified'}\n` +
1208
- `**Port:** ${proxyInfo.port || 'Not specified'}\n` +
1209
- `**Authentication:** ${proxyInfo.proxyUserName ? '✅ Yes' : '❌ No'}\n` +
1210
- `**IP Type:** ${proxyInfo.ipType || 'IPV4'}`;
1211
- }
1212
- else {
1213
- resultText = `❌ **Proxy Configuration Invalid**\n\n` +
1214
- `**Errors:**\n` +
1215
- validation.errors.map(error => ` • ${error}`).join('\n');
1216
- }
1217
- if (validation.warnings.length > 0) {
1218
- resultText += `\n\n**⚠️ Warnings:**\n` +
1219
- validation.warnings.map(warning => ` • ${warning}`).join('\n');
1220
- }
1221
- return {
1222
- content: [
1223
- {
1224
- type: 'text',
1225
- text: resultText,
1226
- },
1227
- ],
1228
- };
1229
- }
1230
- async handleListWorkspaces(args) {
1231
- const { pageIndex = 1, pageSize = 15 } = args || {};
1232
- const data = await this.roxyClient.getWorkspaces(pageIndex, pageSize);
1233
- return {
1234
- content: [
1235
- {
1236
- type: 'text',
1237
- text: `Found ${data.total} workspaces:\n\n` +
1238
- data.rows.map(ws => `**${ws.workspaceName}** (ID: ${ws.id})\n` +
1239
- ws.project_details.map(proj => ` - ${proj.projectName} (ID: ${proj.projectId})`).join('\n')).join('\n\n'),
1240
- },
1241
- ],
1242
- };
1243
- }
1244
- async handleListBrowsers(args) {
1245
- const params = args;
1246
- if (!params.workspaceId) {
1247
- throw new Error('workspaceId is required');
1248
- }
1249
- const data = await this.roxyClient.getBrowsers({
1250
- workspaceId: params.workspaceId,
1251
- projectIds: params.projectIds,
1252
- windowName: params.windowName,
1253
- page_index: params.pageIndex || 1,
1254
- page_size: params.pageSize || 15,
1255
- });
1256
- return {
1257
- content: [
1258
- {
1259
- type: 'text',
1260
- text: `Found ${data.total} browsers in workspace ${params.workspaceId}:\n\n` +
1261
- data.rows.map(browser => `**${browser.windowName || 'Unnamed'}** (ID: ${browser.dirId})\n` +
1262
- ` - Project: ${browser.projectId}\n` +
1263
- ` - Sort: ${browser.sortNum}\n` +
1264
- ` - OS: ${browser.os}\n` +
1265
- ` - Status: ${browser.status}`).join('\n\n'),
1266
- },
1267
- ],
1268
- };
1269
- }
1270
- async handleOpenBrowsers(args) {
1271
- const params = args;
1272
- if (!params.workspaceId || !params.dirIds || params.dirIds.length === 0) {
1273
- throw new Error('workspaceId and dirIds are required');
1274
- }
1275
- const { successes, failures } = await this.roxyClient.openBrowsers(params.workspaceId, params.dirIds, params.args);
1276
- // Build success message
1277
- let message = '';
1278
- if (successes.length > 0) {
1279
- message += `✅ **Successfully opened ${successes.length} browser(s):**\n\n` +
1280
- successes.map(result => `**Browser ${result.dirId || 'Unknown'}** (PID: ${result.pid})\n` +
1281
- ` - CDP WebSocket: \`${result.ws}\`\n` +
1282
- ` - HTTP Endpoint: \`${result.http}\`\n` +
1283
- ` - Core Version: ${result.coreVersion}`).join('\n\n') +
1284
- '\n\n**Use these WebSocket URLs with playwright-mcp:**\n' +
1285
- '```bash\n' +
1286
- successes.map(result => `npx @playwright/mcp@latest --cdp-endpoint "${result.ws}"`).join('\n') +
1287
- '\n```';
1288
- }
1289
- // Build failure message with special handling for quota errors
1290
- if (failures.length > 0) {
1291
- if (successes.length > 0) {
1292
- message += '\n\n---\n\n';
1293
- }
1294
- // Check if any failures are quota errors (code 101 or 409)
1295
- const quotaErrors = failures.filter(f => f.errorCode === 101 || (f.errorCode === 409 && f.error.includes('额度不足')));
1296
- const otherErrors = failures.filter(f => !quotaErrors.includes(f));
1297
- if (quotaErrors.length > 0) {
1298
- message += `❌ **Failed to open ${quotaErrors.length} browser(s) - Insufficient Profiles Quota / 窗口额度不足:**\n\n`;
1299
- quotaErrors.forEach(failure => {
1300
- message += ` - Browser ID: \`${failure.dirId}\`\n Error: ${failure.error}\n`;
1301
- });
1302
- message += '\n**解决步骤 / Solution Steps:**\n';
1303
- message += '1. 打开 RoxyBrowser 应用 / Open RoxyBrowser app\n';
1304
- message += '2. 前往费用中心 / Go to Billing Center\n';
1305
- message += '3. 购买或升级窗口套餐 / Purchase or upgrade profiles plan\n';
1306
- message += '4. 或者删除不需要的浏览器窗口以释放额度 / Or delete unused browser profiles to free up quota\n\n';
1307
- message += '💡 **重要提示 / Important:** 必须使用 `roxy_delete_browsers` 删除浏览器才能释放额度,仅关闭浏览器无法释放额度。\n';
1308
- message += 'You must use `roxy_delete_browsers` to delete profiles to free up quota. Simply closing browsers will NOT free up quota.';
1309
- }
1310
- if (otherErrors.length > 0) {
1311
- if (quotaErrors.length > 0) {
1312
- message += '\n\n';
1313
- }
1314
- message += `❌ **Failed to open ${otherErrors.length} browser(s) - Other Errors:**\n\n`;
1315
- otherErrors.forEach(failure => {
1316
- message += ` - Browser ID: \`${failure.dirId}\`\n`;
1317
- message += ` Error: ${failure.error}\n`;
1318
- message += ` Retryable: ${failure.retryable ? '✅ Yes' : '❌ No'}\n`;
1319
- });
1320
- }
1321
- }
1322
- // If all failed
1323
- if (successes.length === 0 && failures.length > 0) {
1324
- message = `❌ **Failed to open all ${failures.length} browser(s)**\n\n` + message;
1325
- }
1326
- return {
1327
- content: [
1328
- {
1329
- type: 'text',
1330
- text: message,
1331
- },
1332
- ],
1333
- };
1334
- }
1335
- async handleCloseBrowsers(args) {
1336
- const params = args;
1337
- if (!params.dirIds || params.dirIds.length === 0) {
1338
- throw new Error('dirIds are required');
1339
- }
1340
- const results = await this.roxyClient.closeBrowsers(params.dirIds);
1341
- const successCount = results.filter(r => r.success).length;
1342
- const failureCount = results.filter(r => !r.success).length;
1343
- const successText = successCount > 0
1344
- ? `✅ Successfully closed ${successCount} browsers`
1345
- : '';
1346
- const failureText = failureCount > 0
1347
- ? `❌ Failed to close ${failureCount} browsers:\n` +
1348
- results.filter(r => !r.success).map(r => ` - ${r.dirId}: ${r.error}`).join('\n')
1349
- : '';
1350
- return {
1351
- content: [
1352
- {
1353
- type: 'text',
1354
- text: [successText, failureText].filter(Boolean).join('\n\n'),
1355
- },
1356
- ],
1357
- };
1358
- }
1359
- async handleDeleteBrowsers(args) {
1360
- const params = args;
1361
- if (!params.workspaceId || !params.dirIds || params.dirIds.length === 0) {
1362
- throw new Error('workspaceId and dirIds are required');
1363
- }
1364
- try {
1365
- await this.roxyClient.deleteBrowsers(params.workspaceId, params.dirIds);
1366
- const response = {
1367
- results: params.dirIds.map(dirId => ({
1368
- dirId,
1369
- success: true,
1370
- })),
1371
- successCount: params.dirIds.length,
1372
- failureCount: 0,
1373
- message: `Successfully deleted ${params.dirIds.length} browser(s)`,
1374
- };
1375
- return {
1376
- content: [
1377
- {
1378
- type: 'text',
1379
- text: `✅ **Browsers Deleted Successfully**\n\n` +
1380
- `**Count:** ${response.successCount} browser(s)\n` +
1381
- `**Workspace:** ${params.workspaceId}\n\n` +
1382
- `**Deleted Browsers:**\n` +
1383
- params.dirIds.map((dirId, index) => ` ${index + 1}. \`${dirId}\``).join('\n') +
1384
- `\n\n⚠️ **Warning:** Deleted browsers cannot be recovered. All browser data, profiles, and configurations have been permanently removed.`,
1385
- },
1386
- ],
1387
- };
1388
- }
1389
- catch (error) {
1390
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
1391
- return {
1392
- content: [
1393
- {
1394
- type: 'text',
1395
- text: `❌ **Browser Deletion Failed**\n\n` +
1396
- `**Error:** ${errorMessage}\n` +
1397
- `**Workspace:** ${params.workspaceId}\n` +
1398
- `**Failed Browsers:** ${params.dirIds.length}\n\n` +
1399
- `**Browser IDs:**\n` +
1400
- params.dirIds.map((dirId, index) => ` ${index + 1}. \`${dirId}\``).join('\n'),
1401
- },
1402
- ],
1403
- };
1404
- }
1405
- }
1406
- async handleSystemDiagnostics(args) {
1407
- const { includeWorkspaceCheck = true, includeBrowserCheck = true, verbose = false } = args || {};
1408
- // Perform comprehensive diagnostics
1409
- const diagnostics = await this.roxyClient.performDiagnostics();
1410
- let diagnosticText = `## 🔍 系统诊断报告 / System Diagnostics Report\n\n`;
1411
- // Basic connectivity
1412
- diagnosticText += `### 🌐 连接状态 / Connectivity Status\n`;
1413
- diagnosticText += `- **API连接 / API Connection**: ${diagnostics.connected ? '✅ 已连接' : '❌ 连接失败'}\n`;
1414
- diagnosticText += `- **认证状态 / Authentication**: ${diagnostics.authentication ? '✅ 成功' : '❌ 失败'}\n`;
1415
- diagnosticText += `- **工作区访问 / Workspace Access**: ${diagnostics.workspaceAccess ? '✅ 正常' : '⚠️ 受限'}\n\n`;
1416
- // Additional workspace checks
1417
- if (includeWorkspaceCheck && diagnostics.connected && diagnostics.authentication) {
1418
- try {
1419
- const workspaces = await this.roxyClient.getWorkspaces(1, 5);
1420
- diagnosticText += `### 📁 工作区信息 / Workspace Information\n`;
1421
- diagnosticText += `- **可用工作区 / Available Workspaces**: ${workspaces.total}\n`;
1422
- if (workspaces.rows.length > 0) {
1423
- diagnosticText += `- **工作区详情 / Workspace Details**:\n`;
1424
- workspaces.rows.slice(0, 3).forEach(ws => {
1425
- const projectCount = ws.project_details.length;
1426
- diagnosticText += ` - ${ws.workspaceName} (ID: ${ws.id}) - ${projectCount} projects\n`;
1427
- });
1428
- if (workspaces.total > 3) {
1429
- diagnosticText += ` - ... and ${workspaces.total - 3} more\n`;
1430
- }
1431
- }
1432
- diagnosticText += '\n';
1433
- }
1434
- catch (error) {
1435
- diagnosticText += `### 📁 工作区信息 / Workspace Information\n`;
1436
- diagnosticText += `- **状态**: ❌ 无法获取工作区信息\n`;
1437
- diagnosticText += `- **错误**: ${error instanceof Error ? error.message : 'Unknown error'}\n\n`;
1438
- }
1439
- }
1440
- // Browser availability checks
1441
- if (includeBrowserCheck && diagnostics.connected && diagnostics.authentication && diagnostics.workspaceAccess) {
1442
- try {
1443
- // Get first workspace and check browsers
1444
- const workspaces = await this.roxyClient.getWorkspaces(1, 1);
1445
- if (workspaces.rows.length > 0) {
1446
- const firstWorkspace = workspaces.rows[0];
1447
- const browsers = await this.roxyClient.getBrowsers({
1448
- workspaceId: firstWorkspace.id,
1449
- page_index: 1,
1450
- page_size: 5,
1451
- });
1452
- diagnosticText += `### 🖥️ 浏览器状态 / Browser Status\n`;
1453
- diagnosticText += `- **检查工作区 / Checked Workspace**: ${firstWorkspace.workspaceName} (ID: ${firstWorkspace.id})\n`;
1454
- diagnosticText += `- **可用浏览器 / Available Browsers**: ${browsers.total}\n`;
1455
- if (browsers.rows.length > 0) {
1456
- diagnosticText += `- **浏览器示例 / Browser Examples**:\n`;
1457
- browsers.rows.slice(0, 3).forEach(browser => {
1458
- diagnosticText += ` - ${browser.windowName || 'Unnamed'} (${browser.os}) - Status: ${browser.status}\n`;
1459
- });
1460
- }
1461
- diagnosticText += '\n';
1462
- }
1463
- }
1464
- catch (error) {
1465
- diagnosticText += `### 🖥️ 浏览器状态 / Browser Status\n`;
1466
- diagnosticText += `- **状态**: ⚠️ 无法检查浏览器状态\n`;
1467
- diagnosticText += `- **原因**: ${error instanceof Error ? error.message : 'Unknown error'}\n\n`;
1468
- }
1469
- }
1470
- // Error details
1471
- if (diagnostics.errors.length > 0) {
1472
- diagnosticText += `### ❌ 检测到的问题 / Detected Issues\n`;
1473
- diagnostics.errors.forEach((error, index) => {
1474
- diagnosticText += `${index + 1}. ${error}\n`;
1475
- });
1476
- diagnosticText += '\n';
1477
- }
1478
- // Recommendations
1479
- if (diagnostics.recommendations.length > 0) {
1480
- diagnosticText += `### 💡 建议操作 / Recommendations\n`;
1481
- diagnostics.recommendations.slice(0, 8).forEach((rec, index) => {
1482
- diagnosticText += `${index + 1}. ${rec}\n`;
1483
- });
1484
- if (diagnostics.recommendations.length > 8) {
1485
- diagnosticText += `... and ${diagnostics.recommendations.length - 8} more\n`;
1486
- }
1487
- diagnosticText += '\n';
1488
- }
1489
- // Verbose information
1490
- if (verbose) {
1491
- diagnosticText += `### 🔧 详细信息 / Detailed Information\n`;
1492
- diagnosticText += `- **API主机 / API Host**: ${this.roxyClient.config.apiHost}\n`;
1493
- diagnosticText += `- **超时设置 / Timeout**: ${this.roxyClient.config.timeout}ms\n`;
1494
- diagnosticText += `- **诊断时间 / Diagnosis Time**: ${new Date().toISOString()}\n\n`;
1495
- }
1496
- // Overall status
1497
- const overallStatus = diagnostics.connected && diagnostics.authentication;
1498
- diagnosticText += `### 📋 总体状态 / Overall Status\n`;
1499
- diagnosticText += `**${overallStatus ? '✅ 系统正常运行' : '❌ 系统存在问题'}** / `;
1500
- diagnosticText += `**${overallStatus ? 'System Operating Normally' : 'System Issues Detected'}**\n\n`;
1501
- if (overallStatus) {
1502
- diagnosticText += `*系统已准备就绪,可以进行浏览器自动化操作。*\n`;
1503
- diagnosticText += `*System ready for browser automation operations.*`;
1504
- }
1505
- else {
1506
- diagnosticText += `*请解决上述问题后重新运行诊断。*\n`;
1507
- diagnosticText += `*Please resolve the issues above and run diagnostics again.*`;
1508
- }
1509
- return {
1510
- content: [
1511
- {
1512
- type: 'text',
1513
- text: diagnosticText,
1514
- },
1515
- ],
1516
- };
1517
- }
1518
- async handleListAccounts(args) {
1519
- const params = {
1520
- workspaceId: args.workspaceId,
1521
- accountId: args.accountId,
1522
- page_index: args.pageIndex || 1,
1523
- page_size: args.pageSize || 15,
1524
- };
1525
- if (!params.workspaceId) {
1526
- throw new Error('workspaceId is required');
1527
- }
1528
- const data = await this.roxyClient.getAccounts(params);
1529
- return {
1530
- content: [
1531
- {
1532
- type: 'text',
1533
- text: `Found ${data.total} accounts in workspace ${params.workspaceId}:\n\n` +
1534
- data.rows.map(account => `**${account.platformName}** (ID: ${account.id})\n` +
1535
- ` - Username: ${account.platformUserName}\n` +
1536
- ` - Platform URL: ${account.platformUrl}\n` +
1537
- ` - Remarks: ${account.platformRemarks || 'N/A'}\n` +
1538
- ` - Created: ${account.createTime}`).join('\n\n'),
1539
- },
1540
- ],
1541
- };
1542
- }
1543
- async handleListLabels(args) {
1544
- const { workspaceId } = args;
1545
- if (!workspaceId) {
1546
- throw new Error('workspaceId is required');
1547
- }
1548
- const labels = await this.roxyClient.getLabels(workspaceId);
1549
- return {
1550
- content: [
1551
- {
1552
- type: 'text',
1553
- text: `Found ${labels.length} labels in workspace ${workspaceId}:\n\n` +
1554
- labels.map(label => `**${label.name}** (ID: ${label.id})\n` +
1555
- ` - Color: ${label.color}`).join('\n\n'),
1556
- },
1557
- ],
1558
- };
1559
- }
1560
- async handleGetConnectionInfo(args) {
1561
- const { dirIds } = args;
1562
- const connections = await this.roxyClient.getConnectionInfo(dirIds);
1563
- if (connections.length === 0) {
1564
- return {
1565
- content: [
1566
- {
1567
- type: 'text',
1568
- text: '⚠️ No opened browsers found.\n\nUse `roxy_open_browsers` to open browsers first.',
1569
- },
1570
- ],
1571
- };
1572
- }
1573
- return {
1574
- content: [
1575
- {
1576
- type: 'text',
1577
- text: `Found ${connections.length} opened browser(s):\n\n` +
1578
- connections.map(conn => `**${conn.windowName || 'Unnamed'}** (${conn.dirId})\n` +
1579
- ` - PID: ${conn.pid}\n` +
1580
- ` - CDP WebSocket: \`${conn.ws}\`\n` +
1581
- ` - HTTP Endpoint: \`${conn.http}\`\n` +
1582
- ` - Core Version: ${conn.coreVersion}\n` +
1583
- ` - Driver: ${conn.driver}`).join('\n\n'),
1584
- },
1585
- ],
1586
- };
1587
- }
1588
- async handleGetBrowserDetail(args) {
1589
- const { workspaceId, dirId } = args;
1590
- if (!workspaceId || !dirId) {
1591
- throw new Error('workspaceId and dirId are required');
1592
- }
1593
- const detail = await this.roxyClient.getBrowserDetail(workspaceId, dirId);
1594
- // Save cookie count before removing cookies to save tokens
1595
- const cookieCount = detail.cookie?.length || 0;
1596
- // Create a copy without cookies (cookies can be very large)
1597
- const { cookie, ...detailWithoutCookies } = detail;
1598
- // Create summary
1599
- const summary = `**Browser Details Summary**\n\n` +
1600
- `**ID:** \`${detail.dirId}\`\n` +
1601
- `**Name:** ${detail.windowName}\n` +
1602
- `**Sort Number:** ${detail.windowSortNum}\n` +
1603
- `**Project:** ${detail.projectName} (ID: ${detail.projectId})\n` +
1604
- `**OS:** ${detail.os} ${detail.osVersion}\n` +
1605
- `**Core Version:** ${detail.coreVersion}\n` +
1606
- `**Search Engine:** ${detail.searchEngine}\n` +
1607
- `**Open Status:** ${detail.openStatus ? '✅ Opened' : '❌ Closed'}\n` +
1608
- `**Cookies:** ${cookieCount} stored (excluded from response to save tokens)\n\n` +
1609
- `**Full Details (JSON):**\n` +
1610
- '```json\n' +
1611
- JSON.stringify(detailWithoutCookies, null, 2) +
1612
- '\n```';
1613
- return {
1614
- content: [
1615
- {
1616
- type: 'text',
1617
- text: summary,
1618
- },
1619
- ],
1620
- };
1621
- }
1622
- async handleUpdateBrowser(args) {
1623
- const params = args;
1624
- if (!params.workspaceId || !params.dirId) {
1625
- throw new Error('workspaceId and dirId are required');
1626
- }
1627
- await this.roxyClient.updateBrowser(params);
1628
- return {
1629
- content: [
1630
- {
1631
- type: 'text',
1632
- text: `✅ **Browser Updated Successfully**\n\n` +
1633
- `**Browser ID:** \`${params.dirId}\`\n` +
1634
- `**Workspace:** ${params.workspaceId}\n\n` +
1635
- `*Browser configuration has been updated.*`,
1636
- },
1637
- ],
1638
- };
1639
- }
1640
- async handleRandomFingerprint(args) {
1641
- const { workspaceId, dirId } = args;
1642
- if (!workspaceId || !dirId) {
1643
- throw new Error('workspaceId and dirId are required');
1644
- }
1645
- await this.roxyClient.randomBrowserFingerprint(workspaceId, dirId);
1646
- return {
1647
- content: [
1648
- {
1649
- type: 'text',
1650
- text: `✅ **Browser Fingerprint Randomized**\n\n` +
1651
- `**Browser ID:** \`${dirId}\`\n` +
1652
- `**Workspace:** ${workspaceId}\n\n` +
1653
- `*Browser fingerprint has been randomized. Restart the browser to apply changes.*`,
1654
- },
1655
- ],
1656
- };
1657
- }
1658
- async handleClearLocalCache(args) {
1659
- const { dirIds } = args;
1660
- if (!dirIds || dirIds.length === 0) {
1661
- throw new Error('dirIds are required');
1662
- }
1663
- await this.roxyClient.clearBrowserLocalCache(dirIds);
1664
- return {
1665
- content: [
1666
- {
1667
- type: 'text',
1668
- text: `✅ **Local Cache Cleared**\n\n` +
1669
- `**Browser Count:** ${dirIds.length}\n\n` +
1670
- `**Browser IDs:**\n` +
1671
- dirIds.map((id, index) => ` ${index + 1}. \`${id}\``).join('\n'),
1672
- },
1673
- ],
1674
- };
1675
- }
1676
- async handleClearServerCache(args) {
1677
- const { workspaceId, dirIds } = args;
1678
- if (!workspaceId || !dirIds || dirIds.length === 0) {
1679
- throw new Error('workspaceId and dirIds are required');
1680
- }
1681
- await this.roxyClient.clearBrowserServerCache(workspaceId, dirIds);
1682
- return {
1683
- content: [
1684
- {
1685
- type: 'text',
1686
- text: `✅ **Server Cache Cleared**\n\n` +
1687
- `**Workspace:** ${workspaceId}\n` +
1688
- `**Browser Count:** ${dirIds.length}\n\n` +
1689
- `**Browser IDs:**\n` +
1690
- dirIds.map((id, index) => ` ${index + 1}. \`${id}\``).join('\n'),
1691
- },
1692
- ],
1693
- };
1694
- }
1695
149
  async run() {
1696
- // Enhanced connection testing with diagnostics
1697
- console.error('🔗 Performing RoxyBrowser API diagnostics...');
1698
- const diagnostics = await this.roxyClient.performDiagnostics();
1699
- if (!diagnostics.connected) {
1700
- console.error('❌ Failed to connect to RoxyBrowser API');
1701
- console.error('\n📋 Diagnostic Results:');
1702
- diagnostics.errors.forEach(error => console.error(` ❌ ${error}`));
1703
- if (diagnostics.recommendations.length > 0) {
1704
- console.error('\n💡 Recommendations:');
1705
- diagnostics.recommendations.slice(0, 5).forEach((rec, index) => {
1706
- console.error(` ${index + 1}. ${rec}`);
1707
- });
1708
- }
1709
- process.exit(1);
1710
- }
1711
- if (!diagnostics.authentication) {
1712
- console.error('❌ Authentication failed');
1713
- console.error('\n📋 Diagnostic Results:');
1714
- diagnostics.errors.forEach(error => console.error(` ❌ ${error}`));
1715
- if (diagnostics.recommendations.length > 0) {
1716
- console.error('\n💡 Recommendations:');
1717
- diagnostics.recommendations.slice(0, 5).forEach((rec, index) => {
1718
- console.error(` ${index + 1}. ${rec}`);
1719
- });
1720
- }
1721
- process.exit(1);
1722
- }
1723
- console.error('✅ API Diagnostics Passed:');
1724
- console.error(' ✓ Connection established');
1725
- console.error(' ✓ Authentication successful');
1726
- console.error(` ✓ Workspace access: ${diagnostics.workspaceAccess ? 'Yes' : 'Limited'}`);
1727
150
  console.error('🚀 Starting RoxyBrowser MCP Server...');
1728
151
  const transport = new StdioServerTransport();
1729
152
  await this.server.connect(transport);