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