@iflow-mcp/roxybrowserlabs-roxybrowser-mcp-server 1.0.9

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.
@@ -0,0 +1,1502 @@
1
+ import { request } from '../utils/index.js';
2
+ import { proxyList, proxyStore } from './proxy.js';
3
+ const osversion_windows = [
4
+ {
5
+ label: '11',
6
+ type: 'osVersion-Windows',
7
+ value: '11',
8
+ },
9
+ {
10
+ label: '10',
11
+ type: 'osVersion-Windows',
12
+ value: '10',
13
+ },
14
+ {
15
+ label: '8',
16
+ type: 'osVersion-Windows',
17
+ value: '8',
18
+ },
19
+ {
20
+ label: '7',
21
+ type: 'osVersion-Windows',
22
+ value: '7',
23
+ },
24
+ ];
25
+ const osversion_macos = [
26
+ {
27
+ label: '15.3.2',
28
+ type: 'osVersion-macOS',
29
+ value: '15.3.2',
30
+ },
31
+ {
32
+ label: '15.3.1',
33
+ type: 'osVersion-macOS',
34
+ value: '15.3.1',
35
+ },
36
+ {
37
+ label: '15.3',
38
+ type: 'osVersion-macOS',
39
+ value: '15.3',
40
+ },
41
+ {
42
+ label: '15.2',
43
+ type: 'osVersion-macOS',
44
+ value: '15.2',
45
+ },
46
+ {
47
+ label: '15.1',
48
+ type: 'osVersion-macOS',
49
+ value: '15.1',
50
+ },
51
+ {
52
+ label: '15.0.1',
53
+ type: 'osVersion-macOS',
54
+ value: '15.0.1',
55
+ },
56
+ {
57
+ label: '15.0',
58
+ type: 'osVersion-macOS',
59
+ value: '15.0',
60
+ },
61
+ {
62
+ label: '14.7.4',
63
+ type: 'osVersion-macOS',
64
+ value: '14.7.4',
65
+ },
66
+ {
67
+ label: '14.7.3',
68
+ type: 'osVersion-macOS',
69
+ value: '14.7.3',
70
+ },
71
+ {
72
+ label: '14.7.2',
73
+ type: 'osVersion-macOS',
74
+ value: '14.7.2',
75
+ },
76
+ {
77
+ label: '14.7.1',
78
+ type: 'osVersion-macOS',
79
+ value: '14.7.1',
80
+ },
81
+ {
82
+ label: '14.7',
83
+ type: 'osVersion-macOS',
84
+ value: '14.7',
85
+ },
86
+ {
87
+ label: '14.6.1',
88
+ type: 'osVersion-macOS',
89
+ value: '14.6.1',
90
+ },
91
+ {
92
+ label: '14.6',
93
+ type: 'osVersion-macOS',
94
+ value: '14.6',
95
+ },
96
+ {
97
+ label: '14.5',
98
+ type: 'osVersion-macOS',
99
+ value: '14.5',
100
+ },
101
+ {
102
+ label: '14.4.1',
103
+ type: 'osVersion-macOS',
104
+ value: '14.4.1',
105
+ },
106
+ {
107
+ label: '14.4',
108
+ type: 'osVersion-macOS',
109
+ value: '14.4',
110
+ },
111
+ {
112
+ label: '14.3.1',
113
+ type: 'osVersion-macOS',
114
+ value: '14.3.1',
115
+ },
116
+ {
117
+ label: '14.3',
118
+ type: 'osVersion-macOS',
119
+ value: '14.3',
120
+ },
121
+ {
122
+ label: '14.2.1',
123
+ type: 'osVersion-macOS',
124
+ value: '14.2.1',
125
+ },
126
+ {
127
+ label: '14.2',
128
+ type: 'osVersion-macOS',
129
+ value: '14.2',
130
+ },
131
+ {
132
+ label: '14.1',
133
+ type: 'osVersion-macOS',
134
+ value: '14.1',
135
+ },
136
+ {
137
+ label: '13.7.4',
138
+ type: 'osVersion-macOS',
139
+ value: '13.7.4',
140
+ },
141
+ {
142
+ label: '13.7.3',
143
+ type: 'osVersion-macOS',
144
+ value: '13.7.3',
145
+ },
146
+ {
147
+ label: '13.7.2',
148
+ type: 'osVersion-macOS',
149
+ value: '13.7.2',
150
+ },
151
+ {
152
+ label: '13.7.1',
153
+ type: 'osVersion-macOS',
154
+ value: '13.7.1',
155
+ },
156
+ {
157
+ label: '13.7',
158
+ type: 'osVersion-macOS',
159
+ value: '13.7',
160
+ },
161
+ {
162
+ label: 'ALL',
163
+ type: 'osVersion-macOS',
164
+ value: 'ALL',
165
+ },
166
+ ];
167
+ const osversion_linux = [
168
+ {
169
+ label: 'ALL',
170
+ type: 'osVersion-Linux',
171
+ value: 'ALL',
172
+ },
173
+ ];
174
+ const osversion_android = [
175
+ {
176
+ label: '15',
177
+ type: 'osVersion-Android',
178
+ value: '15',
179
+ },
180
+ {
181
+ label: '14',
182
+ type: 'osVersion-Android',
183
+ value: '14',
184
+ },
185
+ {
186
+ label: '13',
187
+ type: 'osVersion-Android',
188
+ value: '13',
189
+ },
190
+ {
191
+ label: '12',
192
+ type: 'osVersion-Android',
193
+ value: '12',
194
+ },
195
+ {
196
+ label: '11',
197
+ type: 'osVersion-Android',
198
+ value: '11',
199
+ },
200
+ {
201
+ label: '10',
202
+ type: 'osVersion-Android',
203
+ value: '10',
204
+ },
205
+ {
206
+ label: '9',
207
+ type: 'osVersion-Android',
208
+ value: '9',
209
+ },
210
+ ];
211
+ const osversion_ios = [
212
+ {
213
+ label: '18.2',
214
+ type: 'osVersion-IOS',
215
+ value: '18.2',
216
+ },
217
+ {
218
+ label: '18.1',
219
+ type: 'osVersion-IOS',
220
+ value: '18.1',
221
+ },
222
+ {
223
+ label: '18.0',
224
+ type: 'osVersion-IOS',
225
+ value: '18.0',
226
+ },
227
+ {
228
+ label: '17.0',
229
+ type: 'osVersion-IOS',
230
+ value: '17.0',
231
+ },
232
+ {
233
+ label: '16.6',
234
+ type: 'osVersion-IOS',
235
+ value: '16.6',
236
+ },
237
+ {
238
+ label: '16.5',
239
+ type: 'osVersion-IOS',
240
+ value: '16.5',
241
+ },
242
+ {
243
+ label: '16.4',
244
+ type: 'osVersion-IOS',
245
+ value: '16.4',
246
+ },
247
+ {
248
+ label: '16.3',
249
+ type: 'osVersion-IOS',
250
+ value: '16.3',
251
+ },
252
+ {
253
+ label: '16.2',
254
+ type: 'osVersion-IOS',
255
+ value: '16.2',
256
+ },
257
+ {
258
+ label: '16.1',
259
+ type: 'osVersion-IOS',
260
+ value: '16.1',
261
+ },
262
+ {
263
+ label: '16.0',
264
+ type: 'osVersion-IOS',
265
+ value: '16.0',
266
+ },
267
+ {
268
+ label: '15.7',
269
+ type: 'osVersion-IOS',
270
+ value: '15.7',
271
+ },
272
+ {
273
+ label: '15.6',
274
+ type: 'osVersion-IOS',
275
+ value: '15.6',
276
+ },
277
+ {
278
+ label: '15.5',
279
+ type: 'osVersion-IOS',
280
+ value: '15.5',
281
+ },
282
+ {
283
+ label: '15.4',
284
+ type: 'osVersion-IOS',
285
+ value: '15.4',
286
+ },
287
+ {
288
+ label: '15.3',
289
+ type: 'osVersion-IOS',
290
+ value: '15.3',
291
+ },
292
+ {
293
+ label: '15.2',
294
+ type: 'osVersion-IOS',
295
+ value: '15.2',
296
+ },
297
+ {
298
+ label: '15.1',
299
+ type: 'osVersion-IOS',
300
+ value: '15.1',
301
+ },
302
+ {
303
+ label: '15.0',
304
+ type: 'osVersion-IOS',
305
+ value: '15.0',
306
+ },
307
+ {
308
+ label: '14.7',
309
+ type: 'osVersion-IOS',
310
+ value: '14.7',
311
+ },
312
+ {
313
+ label: '14.6',
314
+ type: 'osVersion-IOS',
315
+ value: '14.6',
316
+ },
317
+ {
318
+ label: '14.5',
319
+ type: 'osVersion-IOS',
320
+ value: '14.5',
321
+ },
322
+ {
323
+ label: '14.4',
324
+ type: 'osVersion-IOS',
325
+ value: '14.4',
326
+ },
327
+ {
328
+ label: '14.3',
329
+ type: 'osVersion-IOS',
330
+ value: '14.3',
331
+ },
332
+ {
333
+ label: '14.2',
334
+ type: 'osVersion-IOS',
335
+ value: '14.2',
336
+ },
337
+ {
338
+ label: '14.1',
339
+ type: 'osVersion-IOS',
340
+ value: '14.1',
341
+ },
342
+ {
343
+ label: '14.0',
344
+ type: 'osVersion-IOS',
345
+ value: '14.0',
346
+ },
347
+ ];
348
+ const coreVersion = [
349
+ {
350
+ label: 'RoxyChrome 144',
351
+ type: 'coreVersion',
352
+ value: '144',
353
+ },
354
+ {
355
+ label: 'RoxyChrome 143',
356
+ type: 'coreVersion',
357
+ value: '143',
358
+ },
359
+ {
360
+ label: 'RoxyChrome 142',
361
+ type: 'coreVersion',
362
+ value: '142',
363
+ },
364
+ {
365
+ label: 'RoxyChrome 141',
366
+ type: 'coreVersion',
367
+ value: '141',
368
+ },
369
+ {
370
+ label: 'RoxyChrome 140',
371
+ type: 'coreVersion',
372
+ value: '140',
373
+ },
374
+ {
375
+ label: 'RoxyChrome 139',
376
+ type: 'coreVersion',
377
+ value: '139',
378
+ },
379
+ {
380
+ label: 'RoxyChrome 138',
381
+ type: 'coreVersion',
382
+ value: '138',
383
+ },
384
+ {
385
+ label: 'RoxyChrome 137',
386
+ type: 'coreVersion',
387
+ value: '137',
388
+ },
389
+ {
390
+ label: 'RoxyChrome 136',
391
+ type: 'coreVersion',
392
+ value: '136',
393
+ },
394
+ {
395
+ label: 'RoxyChrome 135',
396
+ type: 'coreVersion',
397
+ value: '135',
398
+ },
399
+ {
400
+ label: 'RoxyChrome 133',
401
+ type: 'coreVersion',
402
+ value: '133',
403
+ },
404
+ {
405
+ label: 'RoxyChrome 130',
406
+ type: 'coreVersion',
407
+ value: '130',
408
+ },
409
+ {
410
+ label: 'RoxyChrome 125',
411
+ type: 'coreVersion',
412
+ value: '125',
413
+ },
414
+ {
415
+ label: 'RoxyChrome 117',
416
+ type: 'coreVersion',
417
+ value: '117',
418
+ },
419
+ {
420
+ label: 'RoxyChrome 109',
421
+ type: 'coreVersion',
422
+ value: '109',
423
+ },
424
+ ];
425
+ function osVersionString() {
426
+ return `Windows: ${osversion_windows.map(item => item.value).join(',')}; macOS: ${osversion_macos.map(item => item.value).join(',')}; Linux: ${osversion_linux.map(item => item.value).join(',')}; Android: ${osversion_android.map(item => item.value).join(',')}; IOS: ${osversion_ios.map(item => item.value).join(',')}`;
427
+ }
428
+ class CreateBrowser {
429
+ name = 'roxy_create_browser';
430
+ description = 'Create a browser with complete configuration control - for expert users needing full parameter access';
431
+ inputSchema = {
432
+ type: 'object',
433
+ properties: {
434
+ workspaceId: {
435
+ type: 'number',
436
+ description: 'Workspace ID',
437
+ },
438
+ windowName: {
439
+ type: 'string',
440
+ description: 'Browser window name',
441
+ },
442
+ coreVersion: {
443
+ type: 'string',
444
+ enum: coreVersion.map(item => item.value),
445
+ description: 'Browser core version. If not provided, the latest available core version will be used.',
446
+ },
447
+ os: {
448
+ type: 'string',
449
+ enum: ['Windows', 'macOS', 'Linux', 'IOS', 'Android'],
450
+ description: 'Operating system (default: Windows)',
451
+ },
452
+ osVersion: {
453
+ type: 'string',
454
+ description: osVersionString(),
455
+ },
456
+ userAgent: {
457
+ type: 'string',
458
+ description: 'Custom user agent',
459
+ },
460
+ cookie: {
461
+ type: 'array',
462
+ description: 'Cookie list',
463
+ items: { type: 'object' },
464
+ },
465
+ searchEngine: {
466
+ type: 'string',
467
+ enum: ['Google', 'Microsoft Bing', 'Yahoo', 'Yandex', 'DuckDuckGo'],
468
+ description: 'Default search engine',
469
+ },
470
+ labelIds: {
471
+ type: 'array',
472
+ items: { type: 'number' },
473
+ description: 'Label IDs to assign',
474
+ },
475
+ defaultOpenUrl: {
476
+ type: 'array',
477
+ items: { type: 'string' },
478
+ description: 'URLs to open by default',
479
+ },
480
+ windowRemark: {
481
+ type: 'string',
482
+ description: 'Window remarks/notes',
483
+ },
484
+ projectId: {
485
+ type: 'number',
486
+ description: 'Project ID',
487
+ },
488
+ windowPlatformList: {
489
+ type: 'array',
490
+ items: {
491
+ type: 'object',
492
+ properties: {
493
+ // 平台账号id,非必传,通过平台账号列表接口【roxy_list_accounts】获取,可以判定已在平台账号列表中的账号,有该参数时其他参数不需要传。
494
+ id: { type: 'number', description: 'Platform account ID, which can be obtained from [roxy_list_accounts] (field: id). Used to bind an account that already exists in the platform account list. If this parameter is provided, other parameters do not need to be passed.' },
495
+ platformUrl: { type: 'string', description: 'Platform URL' },
496
+ platformUserName: { type: 'string', description: 'Platform username' },
497
+ platformPassword: { type: 'string', description: 'Platform password' },
498
+ platformEfa: { type: 'string', description: 'Platform EFA' },
499
+ platformRemarks: { type: 'string', description: 'Platform remarks' },
500
+ },
501
+ },
502
+ description: 'Platform account information',
503
+ },
504
+ proxyInfo: {
505
+ type: 'object',
506
+ description: 'Complete proxy configuration object',
507
+ properties: {
508
+ // 如果有 moduleId ,则其他参数不可传递 (moduleId 可通过 roxy_list_proxies 或 roxy_store_proxies 获取) 优先使用该参数来绑定代理IP
509
+ moduleId: { type: 'number', description: `If moduleId is provided, no other parameters may be passed. (moduleId can be obtained via ${proxyList.name} or ${proxyStore.name}. field: id) Priority to use this parameter to bind proxy IP` },
510
+ proxyMethod: { type: 'string', enum: ['custom', 'choose', 'api'] },
511
+ proxyCategory: { type: 'string', enum: ['noproxy', 'HTTP', 'HTTPS', 'SOCKS5', 'SSH'] },
512
+ ipType: { type: 'string', enum: ['IPV4', 'IPV6'] },
513
+ protocol: { type: 'string', enum: ['HTTP', 'HTTPS', 'SOCKS5'] },
514
+ host: { type: 'string' },
515
+ port: { type: 'string' },
516
+ proxyUserName: { type: 'string' },
517
+ proxyPassword: { type: 'string' },
518
+ refreshUrl: { type: 'string' },
519
+ checkChannel: { type: 'string', enum: ['IPRust.io', 'IP-API', 'IP123.in'] },
520
+ },
521
+ },
522
+ fingerInfo: {
523
+ type: 'object',
524
+ description: 'Complete fingerprint configuration',
525
+ properties: {
526
+ // Language and timezone
527
+ isLanguageBaseIp: { type: 'boolean', description: 'Follow IP for browser language' },
528
+ language: { type: 'string', description: 'Custom browser language' },
529
+ isDisplayLanguageBaseIp: { type: 'boolean', description: 'Follow IP for display language' },
530
+ displayLanguage: { type: 'string', description: 'Custom display language' },
531
+ isTimeZone: { type: 'boolean', description: 'Follow IP for timezone' },
532
+ timeZone: { type: 'string', description: 'Custom timezone' },
533
+ // Geolocation
534
+ position: { type: 'number', enum: [0, 1, 2], description: 'Geolocation prompt: 0=ask, 1=allow, 2=deny' },
535
+ isPositionBaseIp: { type: 'boolean', description: 'Follow IP for geolocation' },
536
+ longitude: { type: 'string', description: 'Custom longitude' },
537
+ latitude: { type: 'string', description: 'Custom latitude' },
538
+ precisionPos: { type: 'string', description: 'Precision in meters' },
539
+ // Media settings
540
+ forbidAudio: { type: 'boolean', description: 'Enable/disable sound' },
541
+ forbidImage: { type: 'boolean', description: 'Enable/disable image loading' },
542
+ forbidMedia: { type: 'boolean', description: 'Enable/disable video playback' },
543
+ // Window settings
544
+ openWidth: { type: 'string', description: 'Window width' },
545
+ openHeight: { type: 'string', description: 'Window height' },
546
+ openBookmarks: { type: 'boolean', description: 'Enable bookmarks' },
547
+ positionSwitch: { type: 'boolean', description: 'Window position switch' },
548
+ windowRatioPosition: { type: 'string', description: 'Window position ratio' },
549
+ isDisplayName: { type: 'boolean', description: 'Show window name in title bar' },
550
+ // Sync settings
551
+ syncBookmark: { type: 'boolean', description: 'Sync bookmarks' },
552
+ syncHistory: { type: 'boolean', description: 'Sync history' },
553
+ syncTab: { type: 'boolean', description: 'Sync tabs' },
554
+ syncCookie: { type: 'boolean', description: 'Sync cookies' },
555
+ syncExtensions: { type: 'boolean', description: 'Sync extensions' },
556
+ syncPassword: { type: 'boolean', description: 'Sync saved passwords' },
557
+ syncIndexedDb: { type: 'boolean', description: 'Sync IndexedDB' },
558
+ syncLocalStorage: { type: 'boolean', description: 'Sync LocalStorage' },
559
+ // Cleanup settings
560
+ clearCacheFile: { type: 'boolean', description: 'Clear cache files on startup' },
561
+ clearCookie: { type: 'boolean', description: 'Clear cookies on startup' },
562
+ clearLocalStorage: { type: 'boolean', description: 'Clear LocalStorage on startup' },
563
+ // Advanced settings
564
+ randomFingerprint: { type: 'boolean', description: 'Generate random fingerprint' },
565
+ forbidSavePassword: { type: 'boolean', description: 'Disable password save prompts' },
566
+ stopOpenNet: { type: 'boolean', description: 'Stop opening if network fails' },
567
+ stopOpenIP: { type: 'boolean', description: 'Stop opening if IP changes' },
568
+ stopOpenPosition: { type: 'boolean', description: 'Stop opening if IP location changes' },
569
+ openWorkbench: { type: 'number', enum: [0, 1, 2], description: 'Open workbench: 0=close, 1=open, 2=follow app' },
570
+ // Display settings
571
+ resolutionType: { type: 'boolean', description: 'Custom resolution vs follow system' },
572
+ resolutionX: { type: 'string', description: 'Custom resolution width' },
573
+ resolutionY: { type: 'string', description: 'Custom resolution height' },
574
+ fontType: { type: 'boolean', description: 'Random fonts vs system fonts' },
575
+ // Browser fingerprint settings
576
+ webRTC: { type: 'number', enum: [0, 1, 2], description: 'WebRTC: 0=replace, 1=real, 2=disable' },
577
+ webGL: { type: 'boolean', description: 'WebGL: random vs real' },
578
+ webGLInfo: { type: 'boolean', description: 'WebGL info: custom vs real' },
579
+ webGLManufacturer: { type: 'string', description: 'Custom WebGL manufacturer' },
580
+ webGLRender: { type: 'string', description: 'Custom WebGL renderer' },
581
+ webGpu: { type: 'string', enum: ['webgl', 'real', 'block'], description: 'WebGPU setting' },
582
+ canvas: { type: 'boolean', description: 'Canvas: random vs real' },
583
+ audioContext: { type: 'boolean', description: 'AudioContext: random vs real' },
584
+ speechVoices: { type: 'boolean', description: 'Speech Voices: random vs real' },
585
+ doNotTrack: { type: 'boolean', description: 'Enable Do Not Track' },
586
+ clientRects: { type: 'boolean', description: 'ClientRects: random vs real' },
587
+ deviceInfo: { type: 'boolean', description: 'Media devices: random vs real' },
588
+ deviceNameSwitch: { type: 'boolean', description: 'Device names: random vs real' },
589
+ macInfo: { type: 'boolean', description: 'MAC address: custom vs real' },
590
+ // Hardware settings
591
+ hardwareConcurrent: { type: 'string', description: 'Hardware concurrency' },
592
+ deviceMemory: { type: 'string', description: 'Device memory' },
593
+ // Security settings
594
+ disableSsl: { type: 'boolean', description: 'SSL fingerprint settings' },
595
+ disableSslList: { type: 'array', items: { type: 'string' }, description: 'SSL feature list' },
596
+ portScanProtect: { type: 'boolean', description: 'Port scan protection' },
597
+ portScanList: { type: 'string', description: 'Port scan whitelist' },
598
+ useGpu: { type: 'boolean', description: 'Use GPU acceleration' },
599
+ sandboxPermission: { type: 'boolean', description: 'Disable sandbox' },
600
+ startupParam: { type: 'string', description: 'Browser startup parameters (--headless=new startup headless)' },
601
+ },
602
+ },
603
+ },
604
+ required: ['workspaceId'],
605
+ };
606
+ get schema() {
607
+ return {
608
+ name: this.name,
609
+ description: this.description,
610
+ inputSchema: this.inputSchema,
611
+ };
612
+ }
613
+ async handle(params) {
614
+ const result = await request('/browser/create', {
615
+ method: 'POST',
616
+ body: JSON.stringify(params),
617
+ });
618
+ const data = result.data;
619
+ let text = '';
620
+ if (result.code !== 0) {
621
+ text = `❌ **Failed to create browser:**\n\n error message: ${result.msg}`;
622
+ }
623
+ else {
624
+ text = `✅ **Simple Browser Created**\n\n`
625
+ + `**Browser ID:** \`${data.dirId}\`\n`
626
+ + `*Use this browser ID with \`roxy_open_browsers\` to start the browser and get CDP endpoints for automation.*`;
627
+ }
628
+ return {
629
+ content: [
630
+ {
631
+ type: 'text',
632
+ text,
633
+ },
634
+ ],
635
+ };
636
+ }
637
+ }
638
+ export const createBrowser = new CreateBrowser();
639
+ class BatchCreateBrowsers {
640
+ name = 'roxy_batch_create_browsers';
641
+ description = 'Create multiple browsers in batch by passing an array of browser configurations';
642
+ inputSchema = {
643
+ type: 'object',
644
+ properties: {
645
+ browsers: {
646
+ type: 'array',
647
+ description: 'Array of browser configuration objects to create',
648
+ items: {
649
+ type: 'object',
650
+ properties: createBrowser.inputSchema.properties,
651
+ required: ['workspaceId'],
652
+ },
653
+ },
654
+ },
655
+ required: ['browsers'],
656
+ };
657
+ get schema() {
658
+ return {
659
+ name: this.name,
660
+ description: this.description,
661
+ inputSchema: this.inputSchema,
662
+ };
663
+ }
664
+ async handle(params) {
665
+ if (!Array.isArray(params.browsers) || params.browsers.length === 0) {
666
+ return {
667
+ content: [
668
+ {
669
+ type: 'text',
670
+ text: '❌ **Failed to create browsers:**\n\n browsers array is required and must not be empty',
671
+ },
672
+ ],
673
+ };
674
+ }
675
+ const results = [];
676
+ const createPromises = params.browsers.map(async (browserParams, index) => {
677
+ try {
678
+ const result = await request('/browser/create', {
679
+ method: 'POST',
680
+ body: JSON.stringify(browserParams),
681
+ });
682
+ if (result.code !== 0) {
683
+ return {
684
+ index,
685
+ success: false,
686
+ error: result.msg,
687
+ };
688
+ }
689
+ return {
690
+ index,
691
+ success: true,
692
+ dirId: result.data?.dirId,
693
+ };
694
+ }
695
+ catch (error) {
696
+ return {
697
+ index,
698
+ success: false,
699
+ error: error.message || 'Unknown error',
700
+ };
701
+ }
702
+ });
703
+ const createResults = await Promise.all(createPromises);
704
+ results.push(...createResults);
705
+ const successResults = results.filter(r => r.success);
706
+ const failureResults = results.filter(r => !r.success);
707
+ const successText = successResults.length > 0
708
+ ? `✅ **Successfully created ${successResults.length} browsers**\n\n${successResults.map(r => ` - #${r.index + 1}${r.dirId ? ` (ID: \`${r.dirId}\`)` : ''}`).join('\n')}`
709
+ : '';
710
+ const failureText = failureResults.length > 0
711
+ ? `❌ **Failed to create ${failureResults.length} browsers:**\n\n${failureResults.map(r => ` - #${r.index + 1}: ${r.error}`).join('\n')}`
712
+ : '';
713
+ const summaryLines = [
714
+ `**Total Requests:** ${results.length}`,
715
+ `**Success:** ${successResults.length}`,
716
+ `**Failed:** ${failureResults.length}`,
717
+ '',
718
+ ...[successText, failureText].filter(Boolean),
719
+ ];
720
+ const summaryText = summaryLines.join('\n');
721
+ return {
722
+ content: [
723
+ {
724
+ type: 'text',
725
+ text: summaryText,
726
+ },
727
+ ],
728
+ };
729
+ }
730
+ }
731
+ export const batchCreateBrowsers = new BatchCreateBrowsers();
732
+ class UpdateBrowser {
733
+ name = 'roxy_update_browser';
734
+ description = 'Update a browser with complete configuration control - for expert users needing full parameter access';
735
+ inputSchema = {
736
+ type: 'object',
737
+ properties: {
738
+ ...createBrowser.inputSchema.properties,
739
+ },
740
+ required: ['workspaceId', 'dirId'],
741
+ };
742
+ get schema() {
743
+ return {
744
+ name: this.name,
745
+ description: this.description,
746
+ inputSchema: this.inputSchema,
747
+ };
748
+ }
749
+ async handle(params) {
750
+ const result = await request('/browser/mdf', {
751
+ method: 'POST',
752
+ body: JSON.stringify(params),
753
+ });
754
+ let text = '';
755
+ if (result.code !== 0) {
756
+ text = `❌ **Failed to update browser:**\n\n error message: ${result.msg}`;
757
+ }
758
+ else {
759
+ text = '✅ **Browser Updated Successfully**';
760
+ }
761
+ return {
762
+ content: [
763
+ {
764
+ type: 'text',
765
+ text,
766
+ },
767
+ ],
768
+ };
769
+ }
770
+ }
771
+ class OpenBrowser {
772
+ name = 'roxy_open_browsers';
773
+ description = 'Open one or multiple browsers and return their CDP WebSocket endpoints for automation';
774
+ inputSchema = {
775
+ type: 'object',
776
+ properties: {
777
+ workspaceId: {
778
+ type: 'number',
779
+ description: 'Workspace ID',
780
+ },
781
+ dirIds: {
782
+ type: 'array',
783
+ items: { type: 'string' },
784
+ description: 'Array of browser directory IDs to open',
785
+ },
786
+ forceOpen: {
787
+ type: 'boolean',
788
+ // 即使浏览器已被其他用户打开,还是强制打开
789
+ description: 'Force open browser even if it is already opened by other users (default: true)',
790
+ default: true,
791
+ },
792
+ args: {
793
+ type: 'array',
794
+ items: { type: 'string' },
795
+ description: 'Optional browser startup arguments (--headless=new startup headless)',
796
+ },
797
+ },
798
+ required: ['workspaceId', 'dirIds'],
799
+ };
800
+ get schema() {
801
+ return {
802
+ name: this.name,
803
+ description: this.description,
804
+ inputSchema: this.inputSchema,
805
+ };
806
+ }
807
+ async handle(params) {
808
+ const { workspaceId, dirIds, forceOpen = true, args } = params;
809
+ if (!workspaceId || !Array.isArray(dirIds) || dirIds.length === 0) {
810
+ return {
811
+ content: [
812
+ {
813
+ type: 'text',
814
+ text: '❌ **Failed to open browsers:**\n\n workspaceId and dirIds are required, and dirIds must not be empty',
815
+ },
816
+ ],
817
+ };
818
+ }
819
+ const results = [];
820
+ const openPromises = dirIds.map(async (dirId) => {
821
+ try {
822
+ const result = await request('/browser/open', {
823
+ method: 'POST',
824
+ body: JSON.stringify({
825
+ workspaceId,
826
+ dirId,
827
+ forceOpen,
828
+ args,
829
+ }),
830
+ });
831
+ if (result.code !== 0) {
832
+ return {
833
+ dirId,
834
+ success: false,
835
+ error: result.msg,
836
+ };
837
+ }
838
+ return {
839
+ dirId,
840
+ success: true,
841
+ data: result.data,
842
+ };
843
+ }
844
+ catch (error) {
845
+ return {
846
+ dirId,
847
+ success: false,
848
+ error: error.message || 'Unknown error',
849
+ };
850
+ }
851
+ });
852
+ const openResults = await Promise.all(openPromises);
853
+ results.push(...openResults);
854
+ const successResults = results.filter(r => r.success);
855
+ const failureResults = results.filter(r => !r.success);
856
+ const successText = successResults.length > 0
857
+ ? [
858
+ `✅ **Successfully opened ${successResults.length} browser(s):**`,
859
+ '',
860
+ ...successResults.map((r) => {
861
+ const data = r.data || {};
862
+ return [
863
+ `**Browser ${data.dirId || r.dirId || 'Unknown'}** (PID:${data.pid ?? 'Unknown'})`,
864
+ ` - CDP WebSocket: \`${data.ws ?? 'N/A'}\``,
865
+ ` - HTTP Endpoint: \`${data.http ?? 'N/A'}\``,
866
+ ` - Core Version: ${data.coreVersion ?? 'Unknown'}`,
867
+ ].join('\n');
868
+ }),
869
+ ].join('\n')
870
+ : '';
871
+ const failureText = failureResults.length > 0
872
+ ? [
873
+ `❌ **Failed to open ${failureResults.length} browser(s):**`,
874
+ '',
875
+ ...failureResults.map(r => ` - ${r.dirId}: ${r.error}`),
876
+ ].join('\n')
877
+ : '';
878
+ const summaryLines = [
879
+ `**Workspace:** ${workspaceId}`,
880
+ `**Total Requests:** ${results.length}`,
881
+ `**Success:** ${successResults.length}`,
882
+ `**Failed:** ${failureResults.length}`,
883
+ '',
884
+ ...[successText, failureText].filter(Boolean),
885
+ ];
886
+ const summaryText = summaryLines.join('\n');
887
+ return {
888
+ content: [
889
+ {
890
+ type: 'text',
891
+ text: summaryText,
892
+ },
893
+ ],
894
+ };
895
+ }
896
+ }
897
+ class ListBrowsers {
898
+ name = 'roxy_list_browsers';
899
+ description = 'Get list of browsers in specified workspace/project';
900
+ inputSchema = {
901
+ type: 'object',
902
+ properties: {
903
+ workspaceId: {
904
+ type: 'number',
905
+ description: 'Workspace ID',
906
+ },
907
+ projectIds: {
908
+ type: 'string',
909
+ description: 'Comma-separated project IDs',
910
+ },
911
+ windowName: {
912
+ type: 'string',
913
+ description: 'Filter by browser window name',
914
+ },
915
+ pageIndex: {
916
+ type: 'number',
917
+ description: 'Page index for pagination (default: 1)',
918
+ default: 1,
919
+ },
920
+ pageSize: {
921
+ type: 'number',
922
+ description: 'Number of items per page (default: 15)',
923
+ default: 15,
924
+ },
925
+ },
926
+ required: ['workspaceId'],
927
+ };
928
+ get schema() {
929
+ return {
930
+ name: this.name,
931
+ description: this.description,
932
+ inputSchema: this.inputSchema,
933
+ };
934
+ }
935
+ async handle(params) {
936
+ const searchParams = new URLSearchParams();
937
+ searchParams.append('workspaceId', params.workspaceId.toString());
938
+ if (params.projectIds)
939
+ searchParams.append('projectIds', params.projectIds);
940
+ if (params.windowName)
941
+ searchParams.append('windowName', params.windowName);
942
+ if (params.pageIndex)
943
+ searchParams.append('page_index', params.pageIndex.toString());
944
+ if (params.pageSize)
945
+ searchParams.append('page_size', params.pageSize.toString());
946
+ const result = await request(`/browser/list_v3?${searchParams}`, {
947
+ method: 'GET',
948
+ });
949
+ const data = result.data;
950
+ let text = '';
951
+ if (result.code !== 0) {
952
+ text = `❌ **Failed to list browsers:**\n\n error message: ${result.msg}`;
953
+ }
954
+ else {
955
+ text = `Found ${data.total} browsers in workspace ${params.workspaceId}:\n\n${data.rows.map((browser) => `**${browser.windowName || 'Unnamed'}** (ID: ${browser.dirId})\n`
956
+ + ` - Project: ${browser.projectId}\n`
957
+ + ` - Sort: ${browser.sortNum}\n`
958
+ + ` - OS: ${browser.os}\n`
959
+ + ` - Status: ${browser.status}`).join('\n\n')}`;
960
+ }
961
+ return {
962
+ content: [
963
+ {
964
+ type: 'text',
965
+ text,
966
+ },
967
+ ],
968
+ };
969
+ }
970
+ }
971
+ class CloseBrowsers {
972
+ name = 'roxy_close_browsers';
973
+ description = 'Close multiple browsers by their directory IDs';
974
+ inputSchema = {
975
+ type: 'object',
976
+ properties: {
977
+ dirIds: {
978
+ type: 'array',
979
+ items: { type: 'string' },
980
+ description: 'Array of browser directory IDs to close',
981
+ },
982
+ },
983
+ required: ['dirIds'],
984
+ };
985
+ get schema() {
986
+ return {
987
+ name: this.name,
988
+ description: this.description,
989
+ inputSchema: this.inputSchema,
990
+ };
991
+ }
992
+ async handle(params) {
993
+ if (!params.dirIds || params.dirIds.length === 0) {
994
+ return {
995
+ content: [
996
+ {
997
+ type: 'text',
998
+ text: '❌ **Failed to close browsers:**\n\n dirIds are required',
999
+ },
1000
+ ],
1001
+ };
1002
+ }
1003
+ const results = [];
1004
+ // Close browsers in parallel
1005
+ const closePromises = params.dirIds.map(async (dirId) => {
1006
+ try {
1007
+ const result = await request('/browser/close', {
1008
+ method: 'POST',
1009
+ body: JSON.stringify({ dirId }),
1010
+ });
1011
+ if (result.code !== 0) {
1012
+ return { dirId, success: false, error: result.msg };
1013
+ }
1014
+ return { dirId, success: true };
1015
+ }
1016
+ catch (error) {
1017
+ return { dirId, success: false, error: error.message || 'Unknown error' };
1018
+ }
1019
+ });
1020
+ const closeResults = await Promise.all(closePromises);
1021
+ results.push(...closeResults);
1022
+ const successCount = results.filter(r => r.success).length;
1023
+ const failureCount = results.filter(r => !r.success).length;
1024
+ const successText = successCount > 0
1025
+ ? `✅ Successfully closed ${successCount} browsers`
1026
+ : '';
1027
+ const failureText = failureCount > 0
1028
+ ? `❌ Failed to close ${failureCount} browsers:\n${results.filter(r => !r.success).map(r => ` - ${r.dirId}: ${r.error}`).join('\n')}`
1029
+ : '';
1030
+ return {
1031
+ content: [
1032
+ {
1033
+ type: 'text',
1034
+ text: [successText, failureText].filter(Boolean).join('\n\n'),
1035
+ },
1036
+ ],
1037
+ };
1038
+ }
1039
+ }
1040
+ class DeleteBrowsers {
1041
+ name = 'roxy_delete_browsers';
1042
+ description = 'Delete multiple browsers permanently by their directory IDs';
1043
+ inputSchema = {
1044
+ type: 'object',
1045
+ properties: {
1046
+ workspaceId: {
1047
+ type: 'number',
1048
+ description: 'Workspace ID',
1049
+ },
1050
+ dirIds: {
1051
+ type: 'array',
1052
+ items: { type: 'string' },
1053
+ description: 'Array of browser directory IDs to delete',
1054
+ },
1055
+ },
1056
+ required: ['workspaceId', 'dirIds'],
1057
+ };
1058
+ get schema() {
1059
+ return {
1060
+ name: this.name,
1061
+ description: this.description,
1062
+ inputSchema: this.inputSchema,
1063
+ };
1064
+ }
1065
+ async handle(params) {
1066
+ if (!params.workspaceId || !params.dirIds || params.dirIds.length === 0) {
1067
+ return {
1068
+ content: [
1069
+ {
1070
+ type: 'text',
1071
+ text: '❌ **Failed to delete browsers:**\n\n workspaceId and dirIds are required',
1072
+ },
1073
+ ],
1074
+ };
1075
+ }
1076
+ const result = await request('/browser/delete', {
1077
+ method: 'POST',
1078
+ body: JSON.stringify({
1079
+ workspaceId: params.workspaceId,
1080
+ dirIds: params.dirIds,
1081
+ isSoftDelete: true,
1082
+ }),
1083
+ });
1084
+ let text = '';
1085
+ if (result.code !== 0) {
1086
+ text = `❌ **Browser Deletion Failed**\n\n`
1087
+ + `**Error:** ${result.msg}\n`
1088
+ + `**Workspace:** ${params.workspaceId}\n`
1089
+ + `**Failed Browsers:** ${params.dirIds.length}\n\n`
1090
+ + `**Browser IDs:**\n${params.dirIds.map((dirId, index) => ` ${index + 1}. \`${dirId}\``).join('\n')}`;
1091
+ }
1092
+ else {
1093
+ text = `✅ **Browsers Deleted Successfully**\n\n`
1094
+ + `**Count:** ${params.dirIds.length} browser(s)\n`
1095
+ + `**Workspace:** ${params.workspaceId}\n\n`
1096
+ + `**Deleted Browsers:**\n${params.dirIds.map((dirId, index) => ` ${index + 1}. \`${dirId}\``).join('\n')}`;
1097
+ }
1098
+ return {
1099
+ content: [
1100
+ {
1101
+ type: 'text',
1102
+ text,
1103
+ },
1104
+ ],
1105
+ };
1106
+ }
1107
+ }
1108
+ class GetBrowserDetail {
1109
+ name = 'roxy_get_browser_detail';
1110
+ description = 'Get detailed information for a specific browser window';
1111
+ inputSchema = {
1112
+ type: 'object',
1113
+ properties: {
1114
+ workspaceId: {
1115
+ type: 'number',
1116
+ description: 'Workspace ID',
1117
+ },
1118
+ dirId: {
1119
+ type: 'string',
1120
+ description: 'Browser directory ID',
1121
+ },
1122
+ },
1123
+ required: ['workspaceId', 'dirId'],
1124
+ };
1125
+ get schema() {
1126
+ return {
1127
+ name: this.name,
1128
+ description: this.description,
1129
+ inputSchema: this.inputSchema,
1130
+ };
1131
+ }
1132
+ async handle(params) {
1133
+ if (!params.workspaceId || !params.dirId) {
1134
+ return {
1135
+ content: [
1136
+ {
1137
+ type: 'text',
1138
+ text: '❌ **Failed to get browser detail:**\n\n workspaceId and dirId are required',
1139
+ },
1140
+ ],
1141
+ };
1142
+ }
1143
+ const searchParams = new URLSearchParams();
1144
+ searchParams.append('workspaceId', params.workspaceId.toString());
1145
+ searchParams.append('dirId', params.dirId);
1146
+ const result = await request(`/browser/detail?${searchParams}`, {
1147
+ method: 'GET',
1148
+ });
1149
+ let text = '';
1150
+ if (result.code !== 0) {
1151
+ text = `❌ **Failed to get browser detail:**\n\n error message: ${result.msg}`;
1152
+ }
1153
+ else {
1154
+ const detail = result.data.rows && result.data.rows.length > 0 ? result.data.rows[0] : null;
1155
+ if (!detail) {
1156
+ text = '❌ **Browser not found or no data returned**';
1157
+ }
1158
+ else {
1159
+ // Save cookie count before removing cookies to save tokens
1160
+ const cookieCount = detail.cookie?.length || 0;
1161
+ // Create a copy without cookies (cookies can be very large)
1162
+ const { cookie: _cookie, ...detailWithoutCookies } = detail;
1163
+ // Create summary
1164
+ text = `**Browser Details Summary**\n\n`
1165
+ + `**ID:** \`${detail.dirId}\`\n`
1166
+ + `**Name:** ${detail.windowName}\n`
1167
+ + `**Sort Number:** ${detail.windowSortNum}\n`
1168
+ + `**Project:** ${detail.projectName} (ID: ${detail.projectId})\n`
1169
+ + `**OS:** ${detail.os} ${detail.osVersion}\n`
1170
+ + `**Core Version:** ${detail.coreVersion}\n`
1171
+ + `**Search Engine:** ${detail.searchEngine}\n`
1172
+ + `**Open Status:** ${detail.openStatus ? '✅ Opened' : '❌ Closed'}\n`
1173
+ + `**Cookies:** ${cookieCount} stored (excluded from response to save tokens)\n\n`
1174
+ + `**Full Details (JSON):**\n`
1175
+ + `\`\`\`json\n${JSON.stringify(detailWithoutCookies, null, 2)}\n\`\`\``;
1176
+ }
1177
+ }
1178
+ return {
1179
+ content: [
1180
+ {
1181
+ type: 'text',
1182
+ text,
1183
+ },
1184
+ ],
1185
+ };
1186
+ }
1187
+ }
1188
+ class ClearLocalCache {
1189
+ name = 'roxy_clear_local_cache';
1190
+ description = 'Clear local cache for specified browsers';
1191
+ inputSchema = {
1192
+ type: 'object',
1193
+ properties: {
1194
+ dirIds: {
1195
+ type: 'array',
1196
+ items: { type: 'string' },
1197
+ description: 'Array of browser directory IDs',
1198
+ },
1199
+ },
1200
+ required: ['dirIds'],
1201
+ };
1202
+ get schema() {
1203
+ return {
1204
+ name: this.name,
1205
+ description: this.description,
1206
+ inputSchema: this.inputSchema,
1207
+ };
1208
+ }
1209
+ async handle(params) {
1210
+ if (!params.dirIds || params.dirIds.length === 0) {
1211
+ return {
1212
+ content: [
1213
+ {
1214
+ type: 'text',
1215
+ text: '❌ **Failed to clear local cache:**\n\n dirIds are required',
1216
+ },
1217
+ ],
1218
+ };
1219
+ }
1220
+ const result = await request('/browser/clear_local_cache', {
1221
+ method: 'POST',
1222
+ body: JSON.stringify({ dirIds: params.dirIds }),
1223
+ });
1224
+ let text = '';
1225
+ if (result.code !== 0) {
1226
+ text = `❌ **Failed to clear local cache:**\n\n error message: ${result.msg}`;
1227
+ }
1228
+ else {
1229
+ text = `✅ **Local Cache Cleared**
1230
+
1231
+ **Browser Count:** ${params.dirIds.length}
1232
+
1233
+ **Browser IDs:**
1234
+ ${params.dirIds.map((id, index) => ` ${index + 1}. \`${id}\``).join('\n')}`;
1235
+ }
1236
+ return {
1237
+ content: [
1238
+ {
1239
+ type: 'text',
1240
+ text,
1241
+ },
1242
+ ],
1243
+ };
1244
+ }
1245
+ }
1246
+ class ClearServerCache {
1247
+ name = 'roxy_clear_server_cache';
1248
+ description = 'Clear server-side cache for specified browsers';
1249
+ inputSchema = {
1250
+ type: 'object',
1251
+ properties: {
1252
+ workspaceId: {
1253
+ type: 'number',
1254
+ description: 'Workspace ID',
1255
+ },
1256
+ dirIds: {
1257
+ type: 'array',
1258
+ items: { type: 'string' },
1259
+ description: 'Array of browser directory IDs',
1260
+ },
1261
+ },
1262
+ required: ['workspaceId', 'dirIds'],
1263
+ };
1264
+ get schema() {
1265
+ return {
1266
+ name: this.name,
1267
+ description: this.description,
1268
+ inputSchema: this.inputSchema,
1269
+ };
1270
+ }
1271
+ async handle(params) {
1272
+ if (!params.workspaceId || !params.dirIds || params.dirIds.length === 0) {
1273
+ return {
1274
+ content: [
1275
+ {
1276
+ type: 'text',
1277
+ text: '❌ **Failed to clear server cache:**\n\n workspaceId and dirIds are required',
1278
+ },
1279
+ ],
1280
+ };
1281
+ }
1282
+ const result = await request('/browser/clear_server_cache', {
1283
+ method: 'POST',
1284
+ body: JSON.stringify({
1285
+ workspaceId: params.workspaceId,
1286
+ dirIds: params.dirIds,
1287
+ }),
1288
+ });
1289
+ let text = '';
1290
+ if (result.code !== 0) {
1291
+ text = `❌ **Failed to clear server cache:**\n\n error message: ${result.msg}`;
1292
+ }
1293
+ else {
1294
+ text = `✅ **Server Cache Cleared**
1295
+
1296
+ **Workspace:** ${params.workspaceId}
1297
+ **Browser Count:** ${params.dirIds.length}
1298
+
1299
+ **Browser IDs:**
1300
+ ${params.dirIds.map((id, index) => ` ${index + 1}. \`${id}\``).join('\n')}`;
1301
+ }
1302
+ return {
1303
+ content: [
1304
+ {
1305
+ type: 'text',
1306
+ text,
1307
+ },
1308
+ ],
1309
+ };
1310
+ }
1311
+ }
1312
+ class RandomFingerprint {
1313
+ name = 'roxy_random_fingerprint';
1314
+ description = 'Randomize browser fingerprint for a specific browser';
1315
+ inputSchema = {
1316
+ type: 'object',
1317
+ properties: {
1318
+ workspaceId: {
1319
+ type: 'number',
1320
+ description: 'Workspace ID',
1321
+ },
1322
+ dirId: {
1323
+ type: 'string',
1324
+ description: 'Browser directory ID',
1325
+ },
1326
+ },
1327
+ required: ['workspaceId', 'dirId'],
1328
+ };
1329
+ get schema() {
1330
+ return {
1331
+ name: this.name,
1332
+ description: this.description,
1333
+ inputSchema: this.inputSchema,
1334
+ };
1335
+ }
1336
+ async handle(params) {
1337
+ if (!params.workspaceId || !params.dirId) {
1338
+ return {
1339
+ content: [
1340
+ {
1341
+ type: 'text',
1342
+ text: '❌ **Failed to randomize fingerprint:**\n\n workspaceId and dirId are required',
1343
+ },
1344
+ ],
1345
+ };
1346
+ }
1347
+ const result = await request('/browser/random_env', {
1348
+ method: 'POST',
1349
+ body: JSON.stringify({
1350
+ workspaceId: params.workspaceId,
1351
+ dirId: params.dirId,
1352
+ }),
1353
+ });
1354
+ let text = '';
1355
+ if (result.code !== 0) {
1356
+ text = `❌ **Failed to randomize fingerprint:**\n\n error message: ${result.msg}`;
1357
+ }
1358
+ else {
1359
+ text = `✅ **Browser Fingerprint Randomized**
1360
+
1361
+ **Browser ID:** \`${params.dirId}\`
1362
+ **Workspace:** ${params.workspaceId}
1363
+
1364
+ *Browser fingerprint has been randomized. Restart the browser to apply changes.*`;
1365
+ }
1366
+ return {
1367
+ content: [
1368
+ {
1369
+ type: 'text',
1370
+ text,
1371
+ },
1372
+ ],
1373
+ };
1374
+ }
1375
+ }
1376
+ class ListLabels {
1377
+ name = 'roxy_list_labels';
1378
+ description = 'Get list of labels in specified workspace';
1379
+ inputSchema = {
1380
+ type: 'object',
1381
+ properties: {
1382
+ workspaceId: {
1383
+ type: 'number',
1384
+ description: 'Workspace ID',
1385
+ },
1386
+ },
1387
+ required: ['workspaceId'],
1388
+ };
1389
+ get schema() {
1390
+ return {
1391
+ name: this.name,
1392
+ description: this.description,
1393
+ inputSchema: this.inputSchema,
1394
+ };
1395
+ }
1396
+ async handle(params) {
1397
+ if (!params.workspaceId) {
1398
+ return {
1399
+ content: [
1400
+ {
1401
+ type: 'text',
1402
+ text: '❌ **Failed to list labels:**\n\n workspaceId is required',
1403
+ },
1404
+ ],
1405
+ };
1406
+ }
1407
+ const searchParams = new URLSearchParams();
1408
+ searchParams.append('workspaceId', params.workspaceId.toString());
1409
+ const result = await request(`/browser/label?${searchParams}`, {
1410
+ method: 'GET',
1411
+ });
1412
+ let text = '';
1413
+ if (result.code !== 0) {
1414
+ text = `❌ **Failed to list labels:**\n\n error message: ${result.msg}`;
1415
+ }
1416
+ else {
1417
+ const labels = result.data || [];
1418
+ text = `Found ${labels.length} labels in workspace ${params.workspaceId}:\n\n${labels.map((label) => `**${label.name}** (ID: ${label.id})\n`
1419
+ + ` - Color: ${label.color}`).join('\n\n')}`;
1420
+ }
1421
+ return {
1422
+ content: [
1423
+ {
1424
+ type: 'text',
1425
+ text,
1426
+ },
1427
+ ],
1428
+ };
1429
+ }
1430
+ }
1431
+ class GetConnectionInfo {
1432
+ name = 'roxy_get_connection_info';
1433
+ description = 'Get connection information (CDP endpoints, PIDs) for currently opened browsers';
1434
+ inputSchema = {
1435
+ type: 'object',
1436
+ properties: {
1437
+ dirIds: {
1438
+ type: 'array',
1439
+ items: { type: 'string' },
1440
+ description: 'Array of browser directory IDs to query (optional, returns all if not specified)',
1441
+ },
1442
+ },
1443
+ };
1444
+ get schema() {
1445
+ return {
1446
+ name: this.name,
1447
+ description: this.description,
1448
+ inputSchema: this.inputSchema,
1449
+ };
1450
+ }
1451
+ async handle(params) {
1452
+ const searchParams = new URLSearchParams();
1453
+ if (params.dirIds && params.dirIds.length > 0) {
1454
+ searchParams.append('dirIds', params.dirIds.join(','));
1455
+ }
1456
+ const queryString = searchParams.toString();
1457
+ const endpoint = queryString
1458
+ ? `/browser/connection_info?${queryString}`
1459
+ : '/browser/connection_info';
1460
+ const result = await request(endpoint, {
1461
+ method: 'GET',
1462
+ });
1463
+ let text = '';
1464
+ if (result.code !== 0) {
1465
+ text = `❌ **Failed to get connection info:**\n\n error message: ${result.msg}`;
1466
+ }
1467
+ else {
1468
+ const connections = result.data || [];
1469
+ if (connections.length === 0) {
1470
+ text = '⚠️ No opened browsers found.\n\nUse `roxy_open_browsers` to open browsers first.';
1471
+ }
1472
+ else {
1473
+ text = `Found ${connections.length} opened browser(s):\n\n${connections.map((conn) => `**${conn.windowName || 'Unnamed'}** (${conn.dirId})\n`
1474
+ + ` - PID: ${conn.pid}\n`
1475
+ + ` - CDP WebSocket: \`${conn.ws}\`\n`
1476
+ + ` - HTTP Endpoint: \`${conn.http}\`\n`
1477
+ + ` - Core Version: ${conn.coreVersion}\n`
1478
+ + ` - Driver: ${conn.driver}`).join('\n\n')}`;
1479
+ }
1480
+ }
1481
+ return {
1482
+ content: [
1483
+ {
1484
+ type: 'text',
1485
+ text,
1486
+ },
1487
+ ],
1488
+ };
1489
+ }
1490
+ }
1491
+ export const openBrowser = new OpenBrowser();
1492
+ export const updateBrowser = new UpdateBrowser();
1493
+ export const listBrowsers = new ListBrowsers();
1494
+ export const closeBrowsers = new CloseBrowsers();
1495
+ export const deleteBrowsers = new DeleteBrowsers();
1496
+ export const getBrowserDetail = new GetBrowserDetail();
1497
+ export const clearLocalCache = new ClearLocalCache();
1498
+ export const clearServerCache = new ClearServerCache();
1499
+ export const randomFingerprint = new RandomFingerprint();
1500
+ export const listLabels = new ListLabels();
1501
+ export const getConnectionInfo = new GetConnectionInfo();
1502
+ //# sourceMappingURL=browser.js.map