@roxybrowser/openapi 1.0.10-beta.0 → 1.0.10-beta.2

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/lib/index.js CHANGED
@@ -1,167 +1,3063 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * RoxyBrowser MCP Server
4
- *
5
- * Model Context Protocol server for RoxyBrowser automation.
6
- * Supports: CLI startup, programmatic (in-process) startup, and library usage for secondary development.
7
- */
8
2
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
9
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
10
- import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
11
- import { batchCreateAccounts, createAccount, deleteAccounts, listAccounts, modifyAccount } from './modules/account.js';
12
- import { batchCreateBrowsers, clearLocalCache, clearServerCache, closeBrowsers, createBrowser, deleteBrowsers, getBrowserDetail, getConnectionInfo, listBrowsers, listLabels, openBrowser, randomFingerprint, updateBrowser } from './modules/browser.js';
13
- import { healthCheck, listWorkspaces } from './modules/other.js';
14
- import { batchCreateProxies, createProxy, deleteProxies, detectProxy, modifyProxy, proxyList, proxyStore } from './modules/proxy.js';
15
- // ========== Tool Definitions ==========
16
- export const TOOLS = [
17
- listBrowsers.schema,
18
- batchCreateBrowsers.schema,
19
- createBrowser.schema,
20
- openBrowser.schema,
21
- updateBrowser.schema,
22
- closeBrowsers.schema,
23
- deleteBrowsers.schema,
24
- getBrowserDetail.schema,
25
- clearLocalCache.schema,
26
- clearServerCache.schema,
27
- randomFingerprint.schema,
28
- listLabels.schema,
29
- getConnectionInfo.schema,
30
- proxyList.schema,
31
- proxyStore.schema,
32
- createProxy.schema,
33
- batchCreateProxies.schema,
34
- detectProxy.schema,
35
- modifyProxy.schema,
36
- deleteProxies.schema,
37
- // getDetectChannels.schema,
38
- listAccounts.schema,
39
- createAccount.schema,
40
- batchCreateAccounts.schema,
41
- modifyAccount.schema,
42
- deleteAccounts.schema,
43
- listWorkspaces.schema,
44
- healthCheck.schema,
45
- ];
46
- // ========== MCP Server ==========
47
- export class RoxyBrowserMCPServer {
48
- server;
49
- constructor() {
50
- this.server = new Server({
51
- name: 'roxybrowser-openapi-mcp',
52
- version: '1.0.0',
53
- }, {
54
- capabilities: {
55
- tools: {},
4
+ import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
5
+
6
+ // src/types.ts
7
+ var ConfigError = class extends Error {
8
+ constructor(message) {
9
+ super(message);
10
+ this.name = "ConfigError";
11
+ }
12
+ };
13
+
14
+ // src/utils/index.ts
15
+ var DEFAULT_CONFIG = {
16
+ apiHost: "http://127.0.0.1:50000",
17
+ timeout: 3e4
18
+ };
19
+ var ENV_KEYS = {
20
+ apiHost: "ROXY_API_HOST",
21
+ apiKey: "ROXY_API_KEY",
22
+ timeout: "ROXY_TIMEOUT"
23
+ };
24
+ function resolveConfig() {
25
+ const envHost = process.env[ENV_KEYS.apiHost];
26
+ const envKey = process.env[ENV_KEYS.apiKey];
27
+ const envTimeout = process.env[ENV_KEYS.timeout];
28
+ return {
29
+ apiHost: envHost ?? DEFAULT_CONFIG.apiHost,
30
+ apiKey: envKey ?? "",
31
+ timeout: envTimeout != null && envTimeout !== "" ? Number.parseInt(envTimeout, 10) : DEFAULT_CONFIG.timeout
32
+ };
33
+ }
34
+ function requireConfig() {
35
+ const config = resolveConfig();
36
+ if (!config.apiKey || config.apiKey.trim() === "") {
37
+ throw new ConfigError(
38
+ "API key is required. Set ROXY_API_KEY or pass --api-key. Get your key from RoxyBrowser: API \u2192 API\u914D\u7F6E \u2192 API Key"
39
+ );
40
+ }
41
+ return config;
42
+ }
43
+ async function request(endpoint, options = {}) {
44
+ const config = requireConfig();
45
+ const url = `${config.apiHost.replace(/\/$/, "")}${endpoint}`;
46
+ const controller = new AbortController();
47
+ const timeoutId = setTimeout(() => controller.abort(), config.timeout);
48
+ try {
49
+ const response = await fetch(url, {
50
+ ...options,
51
+ headers: {
52
+ "Content-Type": "application/json",
53
+ "token": config.apiKey,
54
+ ...options.headers
55
+ },
56
+ signal: controller.signal
57
+ });
58
+ clearTimeout(timeoutId);
59
+ if (!response.ok) {
60
+ const responseText = await response.text().catch(() => "Unknown error");
61
+ throw new Error(
62
+ `HTTP ${response.status}: ${response.statusText} ${responseText}`
63
+ );
64
+ }
65
+ const result = await response.json();
66
+ return result;
67
+ } catch (error) {
68
+ clearTimeout(timeoutId);
69
+ throw error;
70
+ }
71
+ }
72
+
73
+ // src/modules/account.ts
74
+ var ListAccounts = class {
75
+ name = "roxy_list_accounts";
76
+ description = "Get list of accounts (platform credentials) in specified workspace";
77
+ inputSchema = {
78
+ type: "object",
79
+ properties: {
80
+ workspaceId: {
81
+ type: "number",
82
+ description: "Workspace ID"
83
+ },
84
+ accountId: {
85
+ type: "number",
86
+ description: "Account ID to filter by"
87
+ },
88
+ pageIndex: {
89
+ type: "number",
90
+ description: "Page index for pagination (default: 1)",
91
+ default: 1
92
+ },
93
+ pageSize: {
94
+ type: "number",
95
+ description: "Number of items per page (default: 15)",
96
+ default: 15
97
+ }
98
+ },
99
+ required: ["workspaceId"]
100
+ };
101
+ get schema() {
102
+ return {
103
+ name: this.name,
104
+ description: this.description,
105
+ inputSchema: this.inputSchema
106
+ };
107
+ }
108
+ async handle(params) {
109
+ const searchParams = new URLSearchParams();
110
+ searchParams.append("workspaceId", params.workspaceId.toString());
111
+ if (params.accountId)
112
+ searchParams.append("accountId", params.accountId.toString());
113
+ if (params.pageIndex)
114
+ searchParams.append("page_index", params.pageIndex.toString());
115
+ if (params.pageSize)
116
+ searchParams.append("page_size", params.pageSize.toString());
117
+ const result = await request(`/account/list?${searchParams}`, {
118
+ method: "GET"
119
+ });
120
+ const data = result.data;
121
+ let text = "";
122
+ if (result.code !== 0) {
123
+ text = `\u274C **Failed to list accounts:**
124
+
125
+ error message: ${result.msg}`;
126
+ } else {
127
+ text = `Found ${data.total} accounts in workspace ${params.workspaceId}:
128
+
129
+ ${data.rows.map(
130
+ (account) => `**${account.platformName}** (ID: ${account.id})
131
+ - Username: ${account.platformUserName}
132
+ - Platform URL: ${account.platformUrl}
133
+ - Remarks: ${account.platformRemarks || "N/A"}
134
+ - Created: ${account.createTime}`
135
+ ).join("\n\n")}`;
136
+ }
137
+ return {
138
+ content: [
139
+ {
140
+ type: "text",
141
+ text
142
+ }
143
+ ]
144
+ };
145
+ }
146
+ };
147
+ var CreateAccount = class {
148
+ name = "roxy_create_account";
149
+ description = "Create a new platform account with credentials";
150
+ inputSchema = {
151
+ type: "object",
152
+ properties: {
153
+ workspaceId: {
154
+ type: "number",
155
+ description: "Workspace ID"
156
+ },
157
+ platformUrl: {
158
+ type: "string",
159
+ description: "Business platform URL (e.g., https://www.tiktok.com/)"
160
+ },
161
+ platformUserName: {
162
+ type: "string",
163
+ description: "Account username"
164
+ },
165
+ platformPassword: {
166
+ type: "string",
167
+ description: "Account password"
168
+ },
169
+ platformEfa: {
170
+ type: "string",
171
+ description: "Account EFA"
172
+ },
173
+ platformCookies: {
174
+ type: "array",
175
+ description: "Account cookies",
176
+ items: {
177
+ type: "object",
178
+ properties: {
179
+ name: { type: "string" },
180
+ value: { type: "string" },
181
+ domain: { type: "string" }
182
+ },
183
+ required: ["name", "value", "domain"]
184
+ }
185
+ },
186
+ platformName: {
187
+ type: "string",
188
+ description: "Platform name"
189
+ },
190
+ platformRemarks: {
191
+ type: "string",
192
+ description: "Platform remarks/notes"
193
+ }
194
+ },
195
+ required: ["workspaceId", "platformUrl", "platformUserName", "platformPassword"]
196
+ };
197
+ get schema() {
198
+ return {
199
+ name: this.name,
200
+ description: this.description,
201
+ inputSchema: this.inputSchema
202
+ };
203
+ }
204
+ async handle(params) {
205
+ if (!params.workspaceId || !params.platformUrl || !params.platformUserName || !params.platformPassword) {
206
+ return {
207
+ content: [
208
+ {
209
+ type: "text",
210
+ text: "\u274C **Failed to create account:**\n\n workspaceId, platformUrl, platformUserName, and platformPassword are required"
211
+ }
212
+ ]
213
+ };
214
+ }
215
+ const { workspaceId, ...accountData } = params;
216
+ const result = await request("/account/create", {
217
+ method: "POST",
218
+ body: JSON.stringify({ workspaceId, ...accountData })
219
+ });
220
+ let text = "";
221
+ if (result.code !== 0) {
222
+ text = `\u274C **Failed to create account:**
223
+
224
+ error message: ${result.msg}`;
225
+ } else {
226
+ text = `\u2705 **Account Created Successfully**
227
+
228
+ **Platform:** ${params.platformName || params.platformUrl}
229
+ **Username:** ${params.platformUserName}
230
+ **Platform URL:** ${params.platformUrl}${params.platformRemarks ? `
231
+ **Remarks:** ${params.platformRemarks}` : ""}${params.platformEfa ? `
232
+ **EFA:** ${params.platformEfa}` : ""}${params.platformCookies && params.platformCookies.length > 0 ? `
233
+ **Cookies:** ${params.platformCookies.length} cookie(s)` : ""}
234
+
235
+ *Account has been created successfully.*`;
236
+ }
237
+ return {
238
+ content: [
239
+ {
240
+ type: "text",
241
+ text
242
+ }
243
+ ]
244
+ };
245
+ }
246
+ };
247
+ var BatchCreateAccounts = class {
248
+ name = "roxy_batch_create_accounts";
249
+ description = "Batch create multiple platform accounts";
250
+ inputSchema = {
251
+ type: "object",
252
+ properties: {
253
+ workspaceId: {
254
+ type: "number",
255
+ description: "Workspace ID"
256
+ },
257
+ accountList: {
258
+ type: "array",
259
+ description: "Array of account configurations",
260
+ items: {
261
+ type: "object",
262
+ properties: {
263
+ platformUrl: { type: "string" },
264
+ platformUserName: { type: "string" },
265
+ platformPassword: { type: "string" },
266
+ platformEfa: { type: "string" },
267
+ platformCookies: {
268
+ type: "array",
269
+ items: {
270
+ type: "object",
271
+ properties: {
272
+ name: { type: "string" },
273
+ value: { type: "string" },
274
+ domain: { type: "string" }
275
+ },
276
+ required: ["name", "value", "domain"]
277
+ }
56
278
  },
279
+ platformName: { type: "string" },
280
+ platformRemarks: { type: "string" }
281
+ },
282
+ required: ["platformUrl", "platformUserName", "platformPassword"]
283
+ }
284
+ }
285
+ },
286
+ required: ["workspaceId", "accountList"]
287
+ };
288
+ get schema() {
289
+ return {
290
+ name: this.name,
291
+ description: this.description,
292
+ inputSchema: this.inputSchema
293
+ };
294
+ }
295
+ async handle(params) {
296
+ if (!params.workspaceId || !params.accountList || params.accountList.length === 0) {
297
+ return {
298
+ content: [
299
+ {
300
+ type: "text",
301
+ text: "\u274C **Failed to batch create accounts:**\n\n workspaceId and accountList are required"
302
+ }
303
+ ]
304
+ };
305
+ }
306
+ const { workspaceId, accountList } = params;
307
+ const result = await request("/account/batch_create", {
308
+ method: "POST",
309
+ body: JSON.stringify({ workspaceId, accountList })
310
+ });
311
+ let text = "";
312
+ if (result.code !== 0) {
313
+ text = `\u274C **Failed to batch create accounts:**
314
+
315
+ error message: ${result.msg}`;
316
+ } else {
317
+ text = `\u2705 **Batch Account Creation Successful**
318
+
319
+ **Count:** ${params.accountList.length} account(s)
320
+ **Workspace:** ${params.workspaceId}
321
+
322
+ *All accounts have been created successfully.*`;
323
+ }
324
+ return {
325
+ content: [
326
+ {
327
+ type: "text",
328
+ text
329
+ }
330
+ ]
331
+ };
332
+ }
333
+ };
334
+ var ModifyAccount = class {
335
+ name = "roxy_modify_account";
336
+ description = "Modify/update an existing platform account";
337
+ inputSchema = {
338
+ type: "object",
339
+ properties: {
340
+ workspaceId: {
341
+ type: "number",
342
+ description: "Workspace ID"
343
+ },
344
+ id: {
345
+ type: "number",
346
+ description: "Account ID to modify"
347
+ },
348
+ platformUrl: {
349
+ type: "string",
350
+ description: "Business platform URL"
351
+ },
352
+ platformUserName: {
353
+ type: "string",
354
+ description: "Account username"
355
+ },
356
+ platformPassword: {
357
+ type: "string",
358
+ description: "Account password"
359
+ },
360
+ platformEfa: {
361
+ type: "string",
362
+ description: "Account EFA"
363
+ },
364
+ platformCookies: {
365
+ type: "array",
366
+ description: "Account cookies",
367
+ items: {
368
+ type: "object",
369
+ properties: {
370
+ name: { type: "string" },
371
+ value: { type: "string" },
372
+ domain: { type: "string" }
373
+ },
374
+ required: ["name", "value", "domain"]
375
+ }
376
+ },
377
+ platformName: {
378
+ type: "string",
379
+ description: "Platform name"
380
+ },
381
+ platformRemarks: {
382
+ type: "string",
383
+ description: "Platform remarks/notes"
384
+ }
385
+ },
386
+ required: ["workspaceId", "id"]
387
+ };
388
+ get schema() {
389
+ return {
390
+ name: this.name,
391
+ description: this.description,
392
+ inputSchema: this.inputSchema
393
+ };
394
+ }
395
+ async handle(params) {
396
+ if (!params.workspaceId || !params.id) {
397
+ return {
398
+ content: [
399
+ {
400
+ type: "text",
401
+ text: "\u274C **Failed to modify account:**\n\n workspaceId and id are required"
402
+ }
403
+ ]
404
+ };
405
+ }
406
+ const { workspaceId, ...accountData } = params;
407
+ const result = await request("/account/modify", {
408
+ method: "POST",
409
+ body: JSON.stringify({ workspaceId, ...accountData })
410
+ });
411
+ let text = "";
412
+ if (result.code !== 0) {
413
+ text = `\u274C **Failed to modify account:**
414
+
415
+ error message: ${result.msg}`;
416
+ } else {
417
+ text = `\u2705 **Account Modified Successfully**
418
+
419
+ **Account ID:** ${params.id}${params.platformName ? `
420
+ **Platform:** ${params.platformName}` : ""}${params.platformUrl ? `
421
+ **Platform URL:** ${params.platformUrl}` : ""}${params.platformUserName ? `
422
+ **Username:** ${params.platformUserName}` : ""}${params.platformRemarks ? `
423
+ **Remarks:** ${params.platformRemarks}` : ""}
424
+
425
+ *Account configuration has been updated.*`;
426
+ }
427
+ return {
428
+ content: [
429
+ {
430
+ type: "text",
431
+ text
432
+ }
433
+ ]
434
+ };
435
+ }
436
+ };
437
+ var DeleteAccounts = class {
438
+ name = "roxy_delete_accounts";
439
+ description = "Delete one or more platform accounts";
440
+ inputSchema = {
441
+ type: "object",
442
+ properties: {
443
+ workspaceId: {
444
+ type: "number",
445
+ description: "Workspace ID"
446
+ },
447
+ ids: {
448
+ type: "array",
449
+ items: { type: "number" },
450
+ description: "Array of account IDs to delete"
451
+ }
452
+ },
453
+ required: ["workspaceId", "ids"]
454
+ };
455
+ get schema() {
456
+ return {
457
+ name: this.name,
458
+ description: this.description,
459
+ inputSchema: this.inputSchema
460
+ };
461
+ }
462
+ async handle(params) {
463
+ if (!params.workspaceId || !params.ids || params.ids.length === 0) {
464
+ return {
465
+ content: [
466
+ {
467
+ type: "text",
468
+ text: "\u274C **Failed to delete accounts:**\n\n workspaceId and ids are required"
469
+ }
470
+ ]
471
+ };
472
+ }
473
+ const { workspaceId, ids } = params;
474
+ const result = await request("/account/delete", {
475
+ method: "POST",
476
+ body: JSON.stringify({ workspaceId, ids })
477
+ });
478
+ let text = "";
479
+ if (result.code !== 0) {
480
+ text = `\u274C **Failed to delete accounts:**
481
+
482
+ error message: ${result.msg}`;
483
+ } else {
484
+ text = `\u2705 **Accounts Deleted Successfully**
485
+
486
+ **Count:** ${params.ids.length} account(s)
487
+ **Workspace:** ${params.workspaceId}
488
+
489
+ **Deleted Account IDs:**
490
+ ${params.ids.map((id, index) => ` ${index + 1}. ${id}`).join("\n")}
491
+
492
+ \u26A0\uFE0F **Warning:** Deleted accounts cannot be recovered.`;
493
+ }
494
+ return {
495
+ content: [
496
+ {
497
+ type: "text",
498
+ text
499
+ }
500
+ ]
501
+ };
502
+ }
503
+ };
504
+ var listAccounts = new ListAccounts();
505
+ var createAccount = new CreateAccount();
506
+ var batchCreateAccounts = new BatchCreateAccounts();
507
+ var modifyAccount = new ModifyAccount();
508
+ var deleteAccounts = new DeleteAccounts();
509
+
510
+ // src/modules/proxy.ts
511
+ var channelList = [
512
+ {
513
+ label: "IPRust.io",
514
+ type: "checkChannel",
515
+ value: "http://iprust.io/ip.json"
516
+ },
517
+ {
518
+ label: "IP-API",
519
+ type: "checkChannel",
520
+ value: "http://pro.ip-api.com/json?key=c1ulk9X5j8NKqTV"
521
+ },
522
+ {
523
+ label: "IP123.in",
524
+ type: "checkChannel",
525
+ value: "http://ip123.in/ip.json"
526
+ },
527
+ {
528
+ label: "IPinfo",
529
+ type: "checkChannel",
530
+ value: "http://ipinfo.io"
531
+ }
532
+ ];
533
+ var ProxyList = class {
534
+ name = "roxy_list_proxies";
535
+ /**
536
+ * 仅当用户没有指定商店时调用
537
+ */
538
+ description = "Get list of proxy configurations. If you want to get the list of proxies configurations you've bought, please use `roxy_store_proxies`.";
539
+ inputSchema = {
540
+ type: "object",
541
+ properties: {
542
+ workspaceId: {
543
+ type: "number",
544
+ description: "Workspace ID"
545
+ },
546
+ id: {
547
+ type: "number",
548
+ description: "Filter by proxy ID"
549
+ },
550
+ pageIndex: {
551
+ type: "number",
552
+ description: "Page index for pagination (default: 1)",
553
+ default: 1
554
+ },
555
+ pageSize: {
556
+ type: "number",
557
+ description: "Number of items per page (default: 15)",
558
+ default: 15
559
+ }
560
+ },
561
+ required: ["workspaceId"]
562
+ };
563
+ get schema() {
564
+ return {
565
+ name: this.name,
566
+ description: this.description,
567
+ inputSchema: this.inputSchema
568
+ };
569
+ }
570
+ async handle(params) {
571
+ const searchParams = new URLSearchParams();
572
+ searchParams.append("workspaceId", params.workspaceId);
573
+ if (params.id)
574
+ searchParams.append("id", params.id);
575
+ if (params.page_index)
576
+ searchParams.append("page_index", params.pageIndex);
577
+ if (params.page_size)
578
+ searchParams.append("page_size", params.pageSize);
579
+ if (!params.workspaceId) {
580
+ throw new Error("workspaceId is required");
581
+ }
582
+ const result = await request(`/proxy/list?${searchParams}`);
583
+ let text = "";
584
+ if (result.code === 0) {
585
+ const data = result.data;
586
+ const proxyListText = data.rows.length > 0 ? data.rows.map((proxy, index) => {
587
+ const statusText = proxy.checkStatus === 1 ? "\u2705 available" : proxy.checkStatus === 2 ? "\u274C unavailable" : "\u23F3 not checked";
588
+ const name = `proxy (id: ${proxy.id}) ${proxy.remark ? `remark: ${proxy.remark}` : ""}`;
589
+ const location = proxy.lastCountry ? `${proxy.lastCity || ""}${proxy.lastCity && proxy.lastCountry ? ", " : ""}${proxy.lastCountry}` : null;
590
+ let baseInfo = `${index + 1}. ${statusText} **${name}**
591
+ protocol: ${proxy.protocol || "N/A"}
592
+ ipType: ${proxy.ipType || "N/A"}
593
+ bind profile count: ${proxy.bindCount || "N/A"}
594
+ Detection channel: ${proxy.checkChannel || "N/A"}`;
595
+ const ipInfo = [];
596
+ if (proxy.host && proxy.port) {
597
+ ipInfo.push(...[proxy.host, ":", proxy.port]);
598
+ if (proxy.proxyUserName && proxy.proxyPassword) {
599
+ ipInfo.push(...["@", proxy.proxyUserName, ":", proxy.proxyPassword]);
600
+ }
601
+ }
602
+ if (location) {
603
+ baseInfo += `
604
+ ${ipInfo.length > 0 ? `${ipInfo.join("")}
605
+ ` : ""}
606
+ \u{1F4CD} ${location}`;
607
+ }
608
+ return baseInfo;
609
+ }).join("\n\n") : "";
610
+ text = `\u{1F4CB} **proxy list** (total: ${data.total})
611
+
612
+ ${proxyListText}`;
613
+ } else {
614
+ text = `\u274C **get proxy list failed**
615
+
616
+ ${result.msg}`;
617
+ }
618
+ return { content: [{ type: "text", text }] };
619
+ }
620
+ };
621
+ var ProxyStore = class {
622
+ name = "roxy_store_proxies";
623
+ description = "Get list of proxy configurations in the Proxy Store";
624
+ inputSchema = {
625
+ type: "object",
626
+ properties: {
627
+ workspaceId: {
628
+ type: "number",
629
+ description: "Workspace ID"
630
+ },
631
+ pageIndex: {
632
+ type: "number",
633
+ description: "Page index for pagination (default: 1)",
634
+ default: 1
635
+ },
636
+ pageSize: {
637
+ type: "number",
638
+ description: "Number of items per page (default: 15)",
639
+ default: 15
640
+ },
641
+ type: {
642
+ type: "number",
643
+ description: "Type of proxies to get (0: list_use, 1: available_list)",
644
+ default: 0
645
+ }
646
+ },
647
+ required: ["workspaceId"]
648
+ };
649
+ get schema() {
650
+ return {
651
+ name: this.name,
652
+ description: this.description,
653
+ inputSchema: this.inputSchema
654
+ };
655
+ }
656
+ async handle(params) {
657
+ const searchParams = new URLSearchParams();
658
+ searchParams.append("workspaceId", params.workspaceId.toString());
659
+ if (params.page_index)
660
+ searchParams.append("page_index", params.page_index.toString());
661
+ if (params.page_size)
662
+ searchParams.append("page_size", params.page_size.toString());
663
+ if (params.type)
664
+ searchParams.append("type", params.type.toString());
665
+ const result = await request(`/proxy/bought_list?${searchParams}`);
666
+ let text = "";
667
+ if (result.code === 0) {
668
+ const data = result.data;
669
+ const proxyListText = data.rows.length > 0 ? data.rows.map((proxy, index) => {
670
+ const statusText = proxy.checkStatus === 1 ? "\u2705 available" : proxy.checkStatus === 2 ? "\u274C unavailable" : "\u23F3 not checked";
671
+ const name = `proxy (id: ${proxy.id}) ${proxy.remark ? `remark: ${proxy.remark}` : ""}`;
672
+ const location = proxy.lastCountry ? `${proxy.lastCity || ""}${proxy.lastCity && proxy.lastCountry ? ", " : ""}${proxy.lastCountry}` : null;
673
+ let baseInfo = `${index + 1}. ${statusText} **${name}**
674
+ protocol: ${proxy.protocol || "N/A"}
675
+ ipType: ${proxy.ipType || "N/A"}
676
+ bind profile count: ${proxy.bindCount || "N/A"}
677
+ Detection channel: ${proxy.checkChannel || "N/A"}
678
+ expire date: ${proxy.expireDate}`;
679
+ const ipInfo = [proxy.host, ":", proxy.port];
680
+ if (proxy.proxyUserName) {
681
+ ipInfo.push(...[proxy.proxyUserName, "@", proxy.proxyPassword]);
682
+ }
683
+ if (location) {
684
+ baseInfo += `
685
+ ${ipInfo.join("")}
686
+ \u{1F4CD} ${location}`;
687
+ }
688
+ return baseInfo;
689
+ }).join("\n\n") : "";
690
+ text = `\u{1F4CB} **proxy store** (total: ${data.total})
691
+
692
+ ${proxyListText}`;
693
+ } else {
694
+ text = `\u274C **get proxy store failed**
695
+
696
+ ${result.msg}`;
697
+ }
698
+ return { content: [{ type: "text", text }] };
699
+ }
700
+ };
701
+ var CreateProxy = class {
702
+ name = "roxy_create_proxy";
703
+ description = "Create a new proxy configuration with automatic IP detection";
704
+ inputSchema = {
705
+ type: "object",
706
+ properties: {
707
+ workspaceId: {
708
+ type: "number",
709
+ description: "Workspace ID"
710
+ },
711
+ protocol: {
712
+ type: "string",
713
+ enum: ["HTTP", "HTTPS", "SOCKS5", "SSH"],
714
+ description: "Proxy protocol type"
715
+ },
716
+ host: {
717
+ type: "string",
718
+ description: "Proxy host/IP address"
719
+ },
720
+ port: {
721
+ type: "string",
722
+ description: "Proxy port"
723
+ },
724
+ proxyUserName: {
725
+ type: "string",
726
+ description: "Proxy username"
727
+ },
728
+ proxyPassword: {
729
+ type: "string",
730
+ description: "Proxy password"
731
+ },
732
+ ipType: {
733
+ type: "string",
734
+ enum: ["IPV4", "IPV6"],
735
+ description: "IP type (default: IPV4)"
736
+ },
737
+ checkChannel: {
738
+ type: "string",
739
+ enum: channelList.map((item) => item.label),
740
+ description: "IP detection channel (default: IP123.in)"
741
+ },
742
+ refreshUrl: {
743
+ type: "string",
744
+ description: "Refresh URL for dynamic proxies"
745
+ },
746
+ remark: {
747
+ type: "string",
748
+ description: "Proxy remark/notes"
749
+ }
750
+ },
751
+ required: ["workspaceId", "protocol", "host", "port"]
752
+ };
753
+ get schema() {
754
+ return {
755
+ name: this.name,
756
+ description: this.description,
757
+ inputSchema: this.inputSchema
758
+ };
759
+ }
760
+ async handle(params) {
761
+ if (!params.workspaceId || !params.protocol || !params.host || !params.port) {
762
+ return {
763
+ content: [
764
+ {
765
+ type: "text",
766
+ text: "\u274C **Failed to create proxy:**\n\n workspaceId, protocol, host, and port are required"
767
+ }
768
+ ]
769
+ };
770
+ }
771
+ const { workspaceId, ipType = "IPV4", checkChannel = "IP123.in", ...proxyData } = params;
772
+ const proxyParams = {
773
+ workspaceId,
774
+ ...proxyData,
775
+ ipType,
776
+ checkChannel: checkChannel ? channelList.find((item) => item.label === checkChannel)?.value : null,
777
+ proxyCategory: params.protocol
778
+ };
779
+ const result = await request("/proxy/create", {
780
+ method: "POST",
781
+ body: JSON.stringify(proxyParams)
782
+ });
783
+ let text = "";
784
+ if (result.code !== 0) {
785
+ if (result.data) {
786
+ text = `\u274C **Failed to create proxy:**
787
+
788
+ error message: ${result.msg}
789
+
790
+ ${result.data.map((item) => ` - index: ${item.index}, error message: ${item.msg.join(", ")}`).join("\n")}`;
791
+ } else {
792
+ text = `\u274C **Failed to create proxy:**
793
+
794
+ error message: ${result.msg}`;
795
+ }
796
+ } else {
797
+ text = `\u2705 **Proxy Created Successfully**
798
+
799
+ **Protocol:** ${params.protocol}
800
+ **Host:** ${params.host}:${params.port}${params.proxyUserName ? `
801
+ **Username:** ${params.proxyUserName}` : ""}${params.remark ? `
802
+ **Remark:** ${params.remark}` : ""}${params.checkChannel ? `
803
+ **Check Channel:** ${params.checkChannel}` : ""}
804
+
805
+ *Proxy configuration created. IP detection will be performed automatically.*`;
806
+ }
807
+ return {
808
+ content: [
809
+ {
810
+ type: "text",
811
+ text
812
+ }
813
+ ]
814
+ };
815
+ }
816
+ };
817
+ var BatchCreateProxies = class {
818
+ name = "roxy_batch_create_proxies";
819
+ description = "Batch create multiple proxy configurations";
820
+ inputSchema = {
821
+ type: "object",
822
+ properties: {
823
+ workspaceId: {
824
+ type: "number",
825
+ description: "Workspace ID"
826
+ },
827
+ // checkChannel: {
828
+ // type: 'string',
829
+ // enum: channelList.map(item => item.label),
830
+ // description: 'Default IP detection channel for all proxies',
831
+ // },
832
+ proxyList: {
833
+ type: "array",
834
+ description: "Array of proxy configurations",
835
+ items: {
836
+ type: "object",
837
+ properties: {
838
+ protocol: { type: "string", enum: ["HTTP", "HTTPS", "SOCKS5", "SSH"] },
839
+ host: { type: "string" },
840
+ port: { type: "string" },
841
+ proxyUserName: { type: "string" },
842
+ proxyPassword: { type: "string" },
843
+ ipType: { type: "string", enum: ["IPV4", "IPV6"] },
844
+ checkChannel: { type: "string", enum: channelList.map((item) => item.label) },
845
+ refreshUrl: { type: "string" },
846
+ remark: { type: "string" }
847
+ },
848
+ required: ["protocol", "host", "port"]
849
+ }
850
+ }
851
+ },
852
+ required: ["workspaceId", "proxyList"]
853
+ };
854
+ get schema() {
855
+ return {
856
+ name: this.name,
857
+ description: this.description,
858
+ inputSchema: this.inputSchema
859
+ };
860
+ }
861
+ async handle(params) {
862
+ if (!params.workspaceId || !params.proxyList || params.proxyList.length === 0) {
863
+ return {
864
+ content: [
865
+ {
866
+ type: "text",
867
+ text: "\u274C **Failed to batch create proxies:**\n\n workspaceId and proxyList are required"
868
+ }
869
+ ]
870
+ };
871
+ }
872
+ const { workspaceId, proxyList: proxyList2 } = params;
873
+ proxyList2.forEach((item) => {
874
+ item.ipType = item.ipType ? item.ipType : "IPV4";
875
+ item.checkChannel = item.checkChannel ? channelList.find((channel) => channel.label === item.checkChannel)?.value : null;
876
+ });
877
+ const result = await request("/proxy/batch_create", {
878
+ method: "POST",
879
+ body: JSON.stringify({ workspaceId, proxyList: proxyList2 })
880
+ });
881
+ let text = "";
882
+ if (result.code !== 0) {
883
+ if (result.data) {
884
+ text = `\u274C **Failed to batch create proxies:**
885
+
886
+ error message: ${result.msg}
887
+
888
+ ${result.data.map((item) => ` - index: ${item.index}, error message: ${item.msg.join(", ")}`).join("\n")}`;
889
+ } else {
890
+ text = `\u274C **Failed to batch create proxies:**
891
+
892
+ error message: ${result.msg}`;
893
+ }
894
+ } else {
895
+ text = `\u2705 **Batch Proxy Creation Successful**
896
+
897
+ **Count:** ${params.proxyList.length} proxy/proxies
898
+ **Workspace:** ${params.workspaceId}${params.checkChannel ? `
899
+ **Default Check Channel:** ${params.checkChannel}` : ""}
900
+
901
+ *All proxies have been created. IP detection will be performed automatically.*`;
902
+ }
903
+ return {
904
+ content: [
905
+ {
906
+ type: "text",
907
+ text
908
+ }
909
+ ]
910
+ };
911
+ }
912
+ };
913
+ var DetectProxy = class {
914
+ name = "roxy_detect_proxy";
915
+ description = "Detect/test a proxy configuration and update its IP information";
916
+ inputSchema = {
917
+ type: "object",
918
+ properties: {
919
+ workspaceId: {
920
+ type: "number",
921
+ description: "Workspace ID"
922
+ },
923
+ id: {
924
+ type: "number",
925
+ description: "Proxy ID to detect"
926
+ }
927
+ },
928
+ required: ["workspaceId", "id"]
929
+ };
930
+ get schema() {
931
+ return {
932
+ name: this.name,
933
+ description: this.description,
934
+ inputSchema: this.inputSchema
935
+ };
936
+ }
937
+ async handle(params) {
938
+ if (!params.workspaceId || !params.id) {
939
+ return {
940
+ content: [
941
+ {
942
+ type: "text",
943
+ text: "\u274C **Failed to detect proxy:**\n\n workspaceId and id are required"
944
+ }
945
+ ]
946
+ };
947
+ }
948
+ const { workspaceId, id } = params;
949
+ const result = await request("/proxy/detect", {
950
+ method: "POST",
951
+ body: JSON.stringify({ workspaceId, id })
952
+ });
953
+ let text = "";
954
+ if (result.code !== 0) {
955
+ text = `\u274C **Failed to detect proxy:**
956
+
957
+ error message: ${result.msg}`;
958
+ } else {
959
+ const data = result.data;
960
+ if (data) {
961
+ text = `\u2705 **Proxy Detection ${data.checkStatus === 1 ? "Success" : data.checkStatus === 2 ? "Failed" : ""}**
962
+
963
+ **ip address:** ${data.lastIp}
964
+ **country:** ${data.lastCountry}
965
+ **city:** ${data.lastCity}
966
+ **timezone:** ${data.timezone ? data.timezone : "N/A"}
967
+ `;
968
+ } else {
969
+ text = `\u2705 **Proxy Detection Started**
970
+
971
+ **Proxy ID:** ${params.id}
972
+ **Workspace:** ${params.workspaceId}
973
+
974
+ *Proxy detection is in progress. This may take a few seconds. Use \`roxy_list_proxies\` | \`roxy_store_proxies\` to check the updated status.*
975
+ `;
976
+ }
977
+ }
978
+ return {
979
+ content: [
980
+ {
981
+ type: "text",
982
+ text
983
+ }
984
+ ]
985
+ };
986
+ }
987
+ };
988
+ var ModifyProxy = class {
989
+ name = "roxy_modify_proxy";
990
+ description = "Modify/update an existing proxy configuration";
991
+ inputSchema = {
992
+ type: "object",
993
+ properties: {
994
+ workspaceId: {
995
+ type: "number",
996
+ description: "Workspace ID"
997
+ },
998
+ id: {
999
+ type: "number",
1000
+ description: "Proxy ID to modify"
1001
+ },
1002
+ protocol: {
1003
+ type: "string",
1004
+ enum: ["HTTP", "HTTPS", "SOCKS5", "SSH"],
1005
+ description: "Proxy protocol type"
1006
+ },
1007
+ host: {
1008
+ type: "string",
1009
+ description: "Proxy host/IP address"
1010
+ },
1011
+ port: {
1012
+ type: "string",
1013
+ description: "Proxy port"
1014
+ },
1015
+ proxyUserName: {
1016
+ type: "string",
1017
+ description: "Proxy username"
1018
+ },
1019
+ proxyPassword: {
1020
+ type: "string",
1021
+ description: "Proxy password"
1022
+ },
1023
+ ipType: {
1024
+ type: "string",
1025
+ enum: ["IPV4", "IPV6"],
1026
+ description: "IP type"
1027
+ },
1028
+ checkChannel: {
1029
+ type: "string",
1030
+ enum: channelList.map((item) => item.label),
1031
+ description: "IP detection channel"
1032
+ },
1033
+ refreshUrl: {
1034
+ type: "string",
1035
+ description: "Refresh URL for dynamic proxies"
1036
+ },
1037
+ remark: {
1038
+ type: "string",
1039
+ description: "Proxy remark/notes"
1040
+ }
1041
+ },
1042
+ required: ["workspaceId", "id"]
1043
+ };
1044
+ get schema() {
1045
+ return {
1046
+ name: this.name,
1047
+ description: this.description,
1048
+ inputSchema: this.inputSchema
1049
+ };
1050
+ }
1051
+ async handle(params) {
1052
+ if (!params.workspaceId || !params.id) {
1053
+ return {
1054
+ content: [
1055
+ {
1056
+ type: "text",
1057
+ text: "\u274C **Failed to modify proxy:**\n\n workspaceId and id are required"
1058
+ }
1059
+ ]
1060
+ };
1061
+ }
1062
+ const { workspaceId, checkChannel = "IPRust.io", ...proxyData } = params;
1063
+ const proxyParams = {
1064
+ workspaceId,
1065
+ ...proxyData,
1066
+ checkChannel: checkChannel ? channelList.find((item) => item.label === checkChannel)?.value : null,
1067
+ proxyCategory: params.protocol
1068
+ };
1069
+ const result = await request("/proxy/modify", {
1070
+ method: "POST",
1071
+ body: JSON.stringify(proxyParams)
1072
+ });
1073
+ let text = "";
1074
+ if (result.code !== 0) {
1075
+ text = `\u274C **Failed to modify proxy:**
1076
+
1077
+ error message: ${result.msg}`;
1078
+ } else {
1079
+ text = `\u2705 **Proxy Modified Successfully**
1080
+
1081
+ **Proxy ID:** ${params.id}${params.protocol ? `
1082
+ **Protocol:** ${params.protocol}` : ""}${params.host ? `
1083
+ **Host:** ${params.host}${params.port ? `:${params.port}` : ""}` : ""}${params.remark ? `
1084
+ **Remark:** ${params.remark}` : ""}
1085
+
1086
+ *Proxy configuration has been updated. Use \`roxy_detect_proxy\` to test the new configuration.*`;
1087
+ }
1088
+ return {
1089
+ content: [
1090
+ {
1091
+ type: "text",
1092
+ text
1093
+ }
1094
+ ]
1095
+ };
1096
+ }
1097
+ };
1098
+ var DeleteProxies = class {
1099
+ name = "roxy_delete_proxies";
1100
+ description = "Delete one or more proxy configurations";
1101
+ inputSchema = {
1102
+ type: "object",
1103
+ properties: {
1104
+ workspaceId: {
1105
+ type: "number",
1106
+ description: "Workspace ID"
1107
+ },
1108
+ ids: {
1109
+ type: "array",
1110
+ items: { type: "number" },
1111
+ description: "Array of proxy IDs to delete"
1112
+ }
1113
+ },
1114
+ required: ["workspaceId", "ids"]
1115
+ };
1116
+ get schema() {
1117
+ return {
1118
+ name: this.name,
1119
+ description: this.description,
1120
+ inputSchema: this.inputSchema
1121
+ };
1122
+ }
1123
+ async handle(params) {
1124
+ if (!params.workspaceId || !params.ids || params.ids.length === 0) {
1125
+ return {
1126
+ content: [
1127
+ {
1128
+ type: "text",
1129
+ text: "\u274C **Failed to delete proxies:**\n\n workspaceId and ids are required"
1130
+ }
1131
+ ]
1132
+ };
1133
+ }
1134
+ const { workspaceId, ids } = params;
1135
+ const result = await request("/proxy/delete", {
1136
+ method: "POST",
1137
+ body: JSON.stringify({ workspaceId, ids })
1138
+ });
1139
+ let text = "";
1140
+ if (result.code !== 0) {
1141
+ text = `\u274C **Failed to delete proxies:**
1142
+
1143
+ error message: ${result.msg}`;
1144
+ } else {
1145
+ text = `\u2705 **Proxies Deleted Successfully**
1146
+
1147
+ **Count:** ${params.ids.length} proxy/proxies
1148
+ **Workspace:** ${params.workspaceId}
1149
+
1150
+ **Deleted Proxy IDs:**
1151
+ ${params.ids.map((id, index) => ` ${index + 1}. ${id}`).join("\n")}
1152
+
1153
+ \u26A0\uFE0F **Warning:** Deleted proxies cannot be recovered.`;
1154
+ }
1155
+ return {
1156
+ content: [
1157
+ {
1158
+ type: "text",
1159
+ text
1160
+ }
1161
+ ]
1162
+ };
1163
+ }
1164
+ };
1165
+ var proxyList = new ProxyList();
1166
+ var proxyStore = new ProxyStore();
1167
+ var createProxy = new CreateProxy();
1168
+ var batchCreateProxies = new BatchCreateProxies();
1169
+ var detectProxy = new DetectProxy();
1170
+ var modifyProxy = new ModifyProxy();
1171
+ var deleteProxies = new DeleteProxies();
1172
+
1173
+ // src/modules/browser.ts
1174
+ var osversion_windows = [
1175
+ {
1176
+ label: "11",
1177
+ type: "osVersion-Windows",
1178
+ value: "11"
1179
+ },
1180
+ {
1181
+ label: "10",
1182
+ type: "osVersion-Windows",
1183
+ value: "10"
1184
+ },
1185
+ {
1186
+ label: "8",
1187
+ type: "osVersion-Windows",
1188
+ value: "8"
1189
+ },
1190
+ {
1191
+ label: "7",
1192
+ type: "osVersion-Windows",
1193
+ value: "7"
1194
+ }
1195
+ ];
1196
+ var osversion_macos = [
1197
+ {
1198
+ label: "15.3.2",
1199
+ type: "osVersion-macOS",
1200
+ value: "15.3.2"
1201
+ },
1202
+ {
1203
+ label: "15.3.1",
1204
+ type: "osVersion-macOS",
1205
+ value: "15.3.1"
1206
+ },
1207
+ {
1208
+ label: "15.3",
1209
+ type: "osVersion-macOS",
1210
+ value: "15.3"
1211
+ },
1212
+ {
1213
+ label: "15.2",
1214
+ type: "osVersion-macOS",
1215
+ value: "15.2"
1216
+ },
1217
+ {
1218
+ label: "15.1",
1219
+ type: "osVersion-macOS",
1220
+ value: "15.1"
1221
+ },
1222
+ {
1223
+ label: "15.0.1",
1224
+ type: "osVersion-macOS",
1225
+ value: "15.0.1"
1226
+ },
1227
+ {
1228
+ label: "15.0",
1229
+ type: "osVersion-macOS",
1230
+ value: "15.0"
1231
+ },
1232
+ {
1233
+ label: "14.7.4",
1234
+ type: "osVersion-macOS",
1235
+ value: "14.7.4"
1236
+ },
1237
+ {
1238
+ label: "14.7.3",
1239
+ type: "osVersion-macOS",
1240
+ value: "14.7.3"
1241
+ },
1242
+ {
1243
+ label: "14.7.2",
1244
+ type: "osVersion-macOS",
1245
+ value: "14.7.2"
1246
+ },
1247
+ {
1248
+ label: "14.7.1",
1249
+ type: "osVersion-macOS",
1250
+ value: "14.7.1"
1251
+ },
1252
+ {
1253
+ label: "14.7",
1254
+ type: "osVersion-macOS",
1255
+ value: "14.7"
1256
+ },
1257
+ {
1258
+ label: "14.6.1",
1259
+ type: "osVersion-macOS",
1260
+ value: "14.6.1"
1261
+ },
1262
+ {
1263
+ label: "14.6",
1264
+ type: "osVersion-macOS",
1265
+ value: "14.6"
1266
+ },
1267
+ {
1268
+ label: "14.5",
1269
+ type: "osVersion-macOS",
1270
+ value: "14.5"
1271
+ },
1272
+ {
1273
+ label: "14.4.1",
1274
+ type: "osVersion-macOS",
1275
+ value: "14.4.1"
1276
+ },
1277
+ {
1278
+ label: "14.4",
1279
+ type: "osVersion-macOS",
1280
+ value: "14.4"
1281
+ },
1282
+ {
1283
+ label: "14.3.1",
1284
+ type: "osVersion-macOS",
1285
+ value: "14.3.1"
1286
+ },
1287
+ {
1288
+ label: "14.3",
1289
+ type: "osVersion-macOS",
1290
+ value: "14.3"
1291
+ },
1292
+ {
1293
+ label: "14.2.1",
1294
+ type: "osVersion-macOS",
1295
+ value: "14.2.1"
1296
+ },
1297
+ {
1298
+ label: "14.2",
1299
+ type: "osVersion-macOS",
1300
+ value: "14.2"
1301
+ },
1302
+ {
1303
+ label: "14.1",
1304
+ type: "osVersion-macOS",
1305
+ value: "14.1"
1306
+ },
1307
+ {
1308
+ label: "13.7.4",
1309
+ type: "osVersion-macOS",
1310
+ value: "13.7.4"
1311
+ },
1312
+ {
1313
+ label: "13.7.3",
1314
+ type: "osVersion-macOS",
1315
+ value: "13.7.3"
1316
+ },
1317
+ {
1318
+ label: "13.7.2",
1319
+ type: "osVersion-macOS",
1320
+ value: "13.7.2"
1321
+ },
1322
+ {
1323
+ label: "13.7.1",
1324
+ type: "osVersion-macOS",
1325
+ value: "13.7.1"
1326
+ },
1327
+ {
1328
+ label: "13.7",
1329
+ type: "osVersion-macOS",
1330
+ value: "13.7"
1331
+ },
1332
+ {
1333
+ label: "ALL",
1334
+ type: "osVersion-macOS",
1335
+ value: "ALL"
1336
+ }
1337
+ ];
1338
+ var osversion_linux = [
1339
+ {
1340
+ label: "ALL",
1341
+ type: "osVersion-Linux",
1342
+ value: "ALL"
1343
+ }
1344
+ ];
1345
+ var osversion_android = [
1346
+ {
1347
+ label: "15",
1348
+ type: "osVersion-Android",
1349
+ value: "15"
1350
+ },
1351
+ {
1352
+ label: "14",
1353
+ type: "osVersion-Android",
1354
+ value: "14"
1355
+ },
1356
+ {
1357
+ label: "13",
1358
+ type: "osVersion-Android",
1359
+ value: "13"
1360
+ },
1361
+ {
1362
+ label: "12",
1363
+ type: "osVersion-Android",
1364
+ value: "12"
1365
+ },
1366
+ {
1367
+ label: "11",
1368
+ type: "osVersion-Android",
1369
+ value: "11"
1370
+ },
1371
+ {
1372
+ label: "10",
1373
+ type: "osVersion-Android",
1374
+ value: "10"
1375
+ },
1376
+ {
1377
+ label: "9",
1378
+ type: "osVersion-Android",
1379
+ value: "9"
1380
+ }
1381
+ ];
1382
+ var osversion_ios = [
1383
+ {
1384
+ label: "18.2",
1385
+ type: "osVersion-IOS",
1386
+ value: "18.2"
1387
+ },
1388
+ {
1389
+ label: "18.1",
1390
+ type: "osVersion-IOS",
1391
+ value: "18.1"
1392
+ },
1393
+ {
1394
+ label: "18.0",
1395
+ type: "osVersion-IOS",
1396
+ value: "18.0"
1397
+ },
1398
+ {
1399
+ label: "17.0",
1400
+ type: "osVersion-IOS",
1401
+ value: "17.0"
1402
+ },
1403
+ {
1404
+ label: "16.6",
1405
+ type: "osVersion-IOS",
1406
+ value: "16.6"
1407
+ },
1408
+ {
1409
+ label: "16.5",
1410
+ type: "osVersion-IOS",
1411
+ value: "16.5"
1412
+ },
1413
+ {
1414
+ label: "16.4",
1415
+ type: "osVersion-IOS",
1416
+ value: "16.4"
1417
+ },
1418
+ {
1419
+ label: "16.3",
1420
+ type: "osVersion-IOS",
1421
+ value: "16.3"
1422
+ },
1423
+ {
1424
+ label: "16.2",
1425
+ type: "osVersion-IOS",
1426
+ value: "16.2"
1427
+ },
1428
+ {
1429
+ label: "16.1",
1430
+ type: "osVersion-IOS",
1431
+ value: "16.1"
1432
+ },
1433
+ {
1434
+ label: "16.0",
1435
+ type: "osVersion-IOS",
1436
+ value: "16.0"
1437
+ },
1438
+ {
1439
+ label: "15.7",
1440
+ type: "osVersion-IOS",
1441
+ value: "15.7"
1442
+ },
1443
+ {
1444
+ label: "15.6",
1445
+ type: "osVersion-IOS",
1446
+ value: "15.6"
1447
+ },
1448
+ {
1449
+ label: "15.5",
1450
+ type: "osVersion-IOS",
1451
+ value: "15.5"
1452
+ },
1453
+ {
1454
+ label: "15.4",
1455
+ type: "osVersion-IOS",
1456
+ value: "15.4"
1457
+ },
1458
+ {
1459
+ label: "15.3",
1460
+ type: "osVersion-IOS",
1461
+ value: "15.3"
1462
+ },
1463
+ {
1464
+ label: "15.2",
1465
+ type: "osVersion-IOS",
1466
+ value: "15.2"
1467
+ },
1468
+ {
1469
+ label: "15.1",
1470
+ type: "osVersion-IOS",
1471
+ value: "15.1"
1472
+ },
1473
+ {
1474
+ label: "15.0",
1475
+ type: "osVersion-IOS",
1476
+ value: "15.0"
1477
+ },
1478
+ {
1479
+ label: "14.7",
1480
+ type: "osVersion-IOS",
1481
+ value: "14.7"
1482
+ },
1483
+ {
1484
+ label: "14.6",
1485
+ type: "osVersion-IOS",
1486
+ value: "14.6"
1487
+ },
1488
+ {
1489
+ label: "14.5",
1490
+ type: "osVersion-IOS",
1491
+ value: "14.5"
1492
+ },
1493
+ {
1494
+ label: "14.4",
1495
+ type: "osVersion-IOS",
1496
+ value: "14.4"
1497
+ },
1498
+ {
1499
+ label: "14.3",
1500
+ type: "osVersion-IOS",
1501
+ value: "14.3"
1502
+ },
1503
+ {
1504
+ label: "14.2",
1505
+ type: "osVersion-IOS",
1506
+ value: "14.2"
1507
+ },
1508
+ {
1509
+ label: "14.1",
1510
+ type: "osVersion-IOS",
1511
+ value: "14.1"
1512
+ },
1513
+ {
1514
+ label: "14.0",
1515
+ type: "osVersion-IOS",
1516
+ value: "14.0"
1517
+ }
1518
+ ];
1519
+ var coreVersion = [
1520
+ {
1521
+ label: "RoxyChrome 144",
1522
+ type: "coreVersion",
1523
+ value: "144"
1524
+ },
1525
+ {
1526
+ label: "RoxyChrome 143",
1527
+ type: "coreVersion",
1528
+ value: "143"
1529
+ },
1530
+ {
1531
+ label: "RoxyChrome 142",
1532
+ type: "coreVersion",
1533
+ value: "142"
1534
+ },
1535
+ {
1536
+ label: "RoxyChrome 141",
1537
+ type: "coreVersion",
1538
+ value: "141"
1539
+ },
1540
+ {
1541
+ label: "RoxyChrome 140",
1542
+ type: "coreVersion",
1543
+ value: "140"
1544
+ },
1545
+ {
1546
+ label: "RoxyChrome 139",
1547
+ type: "coreVersion",
1548
+ value: "139"
1549
+ },
1550
+ {
1551
+ label: "RoxyChrome 138",
1552
+ type: "coreVersion",
1553
+ value: "138"
1554
+ },
1555
+ {
1556
+ label: "RoxyChrome 137",
1557
+ type: "coreVersion",
1558
+ value: "137"
1559
+ },
1560
+ {
1561
+ label: "RoxyChrome 136",
1562
+ type: "coreVersion",
1563
+ value: "136"
1564
+ },
1565
+ {
1566
+ label: "RoxyChrome 135",
1567
+ type: "coreVersion",
1568
+ value: "135"
1569
+ },
1570
+ {
1571
+ label: "RoxyChrome 133",
1572
+ type: "coreVersion",
1573
+ value: "133"
1574
+ },
1575
+ {
1576
+ label: "RoxyChrome 130",
1577
+ type: "coreVersion",
1578
+ value: "130"
1579
+ },
1580
+ {
1581
+ label: "RoxyChrome 125",
1582
+ type: "coreVersion",
1583
+ value: "125"
1584
+ },
1585
+ {
1586
+ label: "RoxyChrome 117",
1587
+ type: "coreVersion",
1588
+ value: "117"
1589
+ },
1590
+ {
1591
+ label: "RoxyChrome 109",
1592
+ type: "coreVersion",
1593
+ value: "109"
1594
+ }
1595
+ ];
1596
+ function osVersionString() {
1597
+ 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(",")}`;
1598
+ }
1599
+ var CreateBrowser = class {
1600
+ name = "roxy_create_browser";
1601
+ description = "Create a browser with complete configuration control - for expert users needing full parameter access";
1602
+ inputSchema = {
1603
+ type: "object",
1604
+ properties: {
1605
+ workspaceId: {
1606
+ type: "number",
1607
+ description: "Workspace ID"
1608
+ },
1609
+ windowName: {
1610
+ type: "string",
1611
+ description: "Browser window name"
1612
+ },
1613
+ coreVersion: {
1614
+ type: "string",
1615
+ enum: coreVersion.map((item) => item.value),
1616
+ description: "Browser core version. If not provided, the latest available core version will be used."
1617
+ },
1618
+ os: {
1619
+ type: "string",
1620
+ enum: ["Windows", "macOS", "Linux", "IOS", "Android"],
1621
+ description: "Operating system (default: Windows)"
1622
+ },
1623
+ osVersion: {
1624
+ type: "string",
1625
+ description: osVersionString()
1626
+ },
1627
+ userAgent: {
1628
+ type: "string",
1629
+ description: "Custom user agent"
1630
+ },
1631
+ cookie: {
1632
+ type: "array",
1633
+ description: "Cookie list",
1634
+ items: { type: "object" }
1635
+ },
1636
+ searchEngine: {
1637
+ type: "string",
1638
+ enum: ["Google", "Microsoft Bing", "Yahoo", "Yandex", "DuckDuckGo"],
1639
+ description: "Default search engine"
1640
+ },
1641
+ labelIds: {
1642
+ type: "array",
1643
+ items: { type: "number" },
1644
+ description: "Label IDs to assign"
1645
+ },
1646
+ defaultOpenUrl: {
1647
+ type: "array",
1648
+ items: { type: "string" },
1649
+ description: "URLs to open by default"
1650
+ },
1651
+ windowRemark: {
1652
+ type: "string",
1653
+ description: "Window remarks/notes"
1654
+ },
1655
+ projectId: {
1656
+ type: "number",
1657
+ description: "Project ID"
1658
+ },
1659
+ windowPlatformList: {
1660
+ type: "array",
1661
+ items: {
1662
+ type: "object",
1663
+ properties: {
1664
+ // 平台账号id,非必传,通过平台账号列表接口【roxy_list_accounts】获取,可以判定已在平台账号列表中的账号,有该参数时其他参数不需要传。
1665
+ 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." },
1666
+ platformUrl: { type: "string", description: "Platform URL" },
1667
+ platformUserName: { type: "string", description: "Platform username" },
1668
+ platformPassword: { type: "string", description: "Platform password" },
1669
+ platformEfa: { type: "string", description: "Platform EFA" },
1670
+ platformRemarks: { type: "string", description: "Platform remarks" }
1671
+ }
1672
+ },
1673
+ description: "Platform account information"
1674
+ },
1675
+ proxyInfo: {
1676
+ type: "object",
1677
+ description: "Complete proxy configuration object",
1678
+ properties: {
1679
+ // 如果有 moduleId ,则其他参数不可传递 (moduleId 可通过 roxy_list_proxies 或 roxy_store_proxies 获取) 优先使用该参数来绑定代理IP
1680
+ 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` },
1681
+ proxyMethod: { type: "string", enum: ["custom", "choose", "api"] },
1682
+ proxyCategory: { type: "string", enum: ["noproxy", "HTTP", "HTTPS", "SOCKS5", "SSH"] },
1683
+ ipType: { type: "string", enum: ["IPV4", "IPV6"] },
1684
+ protocol: { type: "string", enum: ["HTTP", "HTTPS", "SOCKS5"] },
1685
+ host: { type: "string" },
1686
+ port: { type: "string" },
1687
+ proxyUserName: { type: "string" },
1688
+ proxyPassword: { type: "string" },
1689
+ refreshUrl: { type: "string" },
1690
+ checkChannel: { type: "string", enum: ["IPRust.io", "IP-API", "IP123.in"] }
1691
+ }
1692
+ },
1693
+ fingerInfo: {
1694
+ type: "object",
1695
+ description: "Complete fingerprint configuration",
1696
+ properties: {
1697
+ // Language and timezone
1698
+ isLanguageBaseIp: { type: "boolean", description: "Follow IP for browser language" },
1699
+ language: { type: "string", description: "Custom browser language" },
1700
+ isDisplayLanguageBaseIp: { type: "boolean", description: "Follow IP for display language" },
1701
+ displayLanguage: { type: "string", description: "Custom display language" },
1702
+ isTimeZone: { type: "boolean", description: "Follow IP for timezone" },
1703
+ timeZone: { type: "string", description: "Custom timezone" },
1704
+ // Geolocation
1705
+ position: { type: "number", enum: [0, 1, 2], description: "Geolocation prompt: 0=ask, 1=allow, 2=deny" },
1706
+ isPositionBaseIp: { type: "boolean", description: "Follow IP for geolocation" },
1707
+ longitude: { type: "string", description: "Custom longitude" },
1708
+ latitude: { type: "string", description: "Custom latitude" },
1709
+ precisionPos: { type: "string", description: "Precision in meters" },
1710
+ // Media settings
1711
+ forbidAudio: { type: "boolean", description: "Enable/disable sound" },
1712
+ forbidImage: { type: "boolean", description: "Enable/disable image loading" },
1713
+ forbiddenPictureSize: { type: "number", description: "Image load size threshold (bytes). When forbidImage is false, set forbiddenPictureSize = 0 to disable all image loading. Default 0." },
1714
+ forbidMedia: { type: "boolean", description: "Enable/disable video playback" },
1715
+ // Window settings
1716
+ openWidth: { type: "string", description: "Window width" },
1717
+ openHeight: { type: "string", description: "Window height" },
1718
+ openBookmarks: { type: "boolean", description: "Enable bookmarks" },
1719
+ positionSwitch: { type: "boolean", description: "Window position switch" },
1720
+ windowRatioPosition: { type: "string", description: "Window position ratio" },
1721
+ isDisplayName: { type: "boolean", description: "Show window name in title bar" },
1722
+ // Sync settings
1723
+ syncBookmark: { type: "boolean", description: "Sync bookmarks" },
1724
+ syncHistory: { type: "boolean", description: "Sync history" },
1725
+ syncTab: { type: "boolean", description: "Sync tabs" },
1726
+ syncCookie: { type: "boolean", description: "Sync cookies" },
1727
+ syncExtensions: { type: "boolean", description: "Sync extensions" },
1728
+ syncPassword: { type: "boolean", description: "Sync saved passwords" },
1729
+ syncIndexedDb: { type: "boolean", description: "Sync IndexedDB" },
1730
+ syncLocalStorage: { type: "boolean", description: "Sync LocalStorage" },
1731
+ // Cleanup settings
1732
+ clearCacheFile: { type: "boolean", description: "Clear cache files on startup" },
1733
+ clearCookie: { type: "boolean", description: "Clear cookies on startup" },
1734
+ clearLocalStorage: { type: "boolean", description: "Clear LocalStorage on startup" },
1735
+ // Advanced settings
1736
+ randomFingerprint: { type: "boolean", description: "Generate random fingerprint" },
1737
+ forbidSavePassword: { type: "boolean", description: "Disable password save prompts" },
1738
+ stopOpenNet: { type: "boolean", description: "Stop opening if network fails" },
1739
+ stopOpenIP: { type: "boolean", description: "Stop opening if IP changes" },
1740
+ stopOpenPosition: { type: "boolean", description: "Stop opening if IP location changes" },
1741
+ openWorkbench: { type: "number", enum: [0, 1, 2], description: "Open workbench: 0=close, 1=open, 2=follow app" },
1742
+ // Display settings
1743
+ resolutionType: { type: "boolean", description: "Custom resolution vs follow system" },
1744
+ resolutionX: { type: "string", description: "Custom resolution width" },
1745
+ resolutionY: { type: "string", description: "Custom resolution height" },
1746
+ fontType: { type: "boolean", description: "Random fonts vs system fonts" },
1747
+ // Browser fingerprint settings
1748
+ webRTC: { type: "number", enum: [0, 1, 2], description: "WebRTC: 0=replace, 1=real, 2=disable" },
1749
+ webGL: { type: "boolean", description: "WebGL: random vs real" },
1750
+ webGLInfo: { type: "boolean", description: "WebGL info: custom vs real" },
1751
+ webGLManufacturer: { type: "string", description: "Custom WebGL manufacturer" },
1752
+ webGLRender: { type: "string", description: "Custom WebGL renderer" },
1753
+ webGpu: { type: "string", enum: ["webgl", "real", "block"], description: "WebGPU setting" },
1754
+ canvas: { type: "boolean", description: "Canvas: random vs real" },
1755
+ audioContext: { type: "boolean", description: "AudioContext: random vs real" },
1756
+ speechVoices: { type: "boolean", description: "Speech Voices: random vs real" },
1757
+ doNotTrack: { type: "boolean", description: "Enable Do Not Track" },
1758
+ clientRects: { type: "boolean", description: "ClientRects: random vs real" },
1759
+ deviceInfo: { type: "boolean", description: "Media devices: random vs real" },
1760
+ deviceNameSwitch: { type: "boolean", description: "Device names: random vs real" },
1761
+ macInfo: { type: "boolean", description: "MAC address: custom vs real" },
1762
+ // Hardware settings
1763
+ hardwareConcurrent: { type: "string", description: "Hardware concurrency" },
1764
+ deviceMemory: { type: "string", description: "Device memory" },
1765
+ // Security settings
1766
+ disableSsl: { type: "boolean", description: "SSL fingerprint settings" },
1767
+ disableSslList: { type: "array", items: { type: "string" }, description: "SSL feature list" },
1768
+ portScanProtect: { type: "boolean", description: "Port scan protection" },
1769
+ portScanList: { type: "string", description: "Port scan whitelist" },
1770
+ useGpu: { type: "boolean", description: "Use GPU acceleration" },
1771
+ sandboxPermission: { type: "boolean", description: "Disable sandbox" },
1772
+ startupParam: { type: "string", description: "Browser startup parameters (--headless=new startup headless)" }
1773
+ }
1774
+ }
1775
+ },
1776
+ required: ["workspaceId"]
1777
+ };
1778
+ get schema() {
1779
+ return {
1780
+ name: this.name,
1781
+ description: this.description,
1782
+ inputSchema: this.inputSchema
1783
+ };
1784
+ }
1785
+ async handle(params) {
1786
+ const result = await request("/browser/create", {
1787
+ method: "POST",
1788
+ body: JSON.stringify(params)
1789
+ });
1790
+ const data = result.data;
1791
+ let text = "";
1792
+ if (result.code !== 0) {
1793
+ text = `\u274C **Failed to create browser:**
1794
+
1795
+ error message: ${result.msg}`;
1796
+ } else {
1797
+ text = `\u2705 **Simple Browser Created**
1798
+
1799
+ **Browser ID:** \`${data.dirId}\`
1800
+ *Use this browser ID with \`roxy_open_browsers\` to start the browser and get CDP endpoints for automation.*`;
1801
+ }
1802
+ return {
1803
+ content: [
1804
+ {
1805
+ type: "text",
1806
+ text
1807
+ }
1808
+ ]
1809
+ };
1810
+ }
1811
+ };
1812
+ var createBrowser = new CreateBrowser();
1813
+ var BatchCreateBrowsers = class {
1814
+ name = "roxy_batch_create_browsers";
1815
+ description = "Create multiple browsers in batch by passing an array of browser configurations";
1816
+ inputSchema = {
1817
+ type: "object",
1818
+ properties: {
1819
+ browsers: {
1820
+ type: "array",
1821
+ description: "Array of browser configuration objects to create",
1822
+ items: {
1823
+ type: "object",
1824
+ properties: createBrowser.inputSchema.properties,
1825
+ required: ["workspaceId"]
1826
+ }
1827
+ }
1828
+ },
1829
+ required: ["browsers"]
1830
+ };
1831
+ get schema() {
1832
+ return {
1833
+ name: this.name,
1834
+ description: this.description,
1835
+ inputSchema: this.inputSchema
1836
+ };
1837
+ }
1838
+ async handle(params) {
1839
+ if (!Array.isArray(params.browsers) || params.browsers.length === 0) {
1840
+ return {
1841
+ content: [
1842
+ {
1843
+ type: "text",
1844
+ text: "\u274C **Failed to create browsers:**\n\n browsers array is required and must not be empty"
1845
+ }
1846
+ ]
1847
+ };
1848
+ }
1849
+ const results = [];
1850
+ const createPromises = params.browsers.map(async (browserParams, index) => {
1851
+ try {
1852
+ const result = await request("/browser/create", {
1853
+ method: "POST",
1854
+ body: JSON.stringify(browserParams)
57
1855
  });
58
- this.setupHandlers();
59
- }
60
- setupHandlers() {
61
- // List available tools
62
- this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
63
- tools: TOOLS,
64
- }));
65
- // Handle tool calls
66
- this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
67
- const { name, arguments: args } = request.params;
68
- try {
69
- switch (name) {
70
- // 浏览器相关
71
- case listBrowsers.name:
72
- return await listBrowsers.handle(args);
73
- case createBrowser.name:
74
- return await createBrowser.handle(args);
75
- case openBrowser.name:
76
- return await openBrowser.handle(args);
77
- case updateBrowser.name:
78
- return await updateBrowser.handle(args);
79
- case closeBrowsers.name:
80
- return await closeBrowsers.handle(args);
81
- case deleteBrowsers.name:
82
- return await deleteBrowsers.handle(args);
83
- case batchCreateBrowsers.name:
84
- return await batchCreateBrowsers.handle(args);
85
- case listLabels.name:
86
- return await listLabels.handle(args);
87
- case getConnectionInfo.name:
88
- return await getConnectionInfo.handle(args);
89
- case randomFingerprint.name:
90
- return await randomFingerprint.handle(args);
91
- case clearLocalCache.name:
92
- return await clearLocalCache.handle(args);
93
- case clearServerCache.name:
94
- return await clearServerCache.handle(args);
95
- case getBrowserDetail.name:
96
- return await getBrowserDetail.handle(args);
97
- // 账号相关
98
- case listAccounts.name:
99
- return await listAccounts.handle(args);
100
- case createAccount.name:
101
- return await createAccount.handle(args);
102
- case batchCreateAccounts.name:
103
- return await batchCreateAccounts.handle(args);
104
- case modifyAccount.name:
105
- return await modifyAccount.handle(args);
106
- case deleteAccounts.name:
107
- return await deleteAccounts.handle(args);
108
- // 代理相关
109
- case proxyList.name:
110
- return await proxyList.handle(args);
111
- case proxyStore.name:
112
- return await proxyStore.handle(args);
113
- case createProxy.name:
114
- return await createProxy.handle(args);
115
- case batchCreateProxies.name:
116
- return await batchCreateProxies.handle(args);
117
- case detectProxy.name:
118
- return await detectProxy.handle(args);
119
- case modifyProxy.name:
120
- return await modifyProxy.handle(args);
121
- case deleteProxies.name:
122
- return await deleteProxies.handle(args);
123
- // 空间列表
124
- case listWorkspaces.name:
125
- return await listWorkspaces.handle(args);
126
- // 健康检查
127
- case healthCheck.name:
128
- return await healthCheck.handle(args);
129
- default:
130
- throw new Error(`Unknown tool: ${name}`);
131
- }
132
- }
133
- catch (error) {
134
- return {
135
- content: [
136
- {
137
- type: 'text',
138
- text: error instanceof Error ? error.message : 'Unknown error',
139
- },
140
- ],
141
- };
1856
+ if (result.code !== 0) {
1857
+ return {
1858
+ index,
1859
+ success: false,
1860
+ error: result.msg
1861
+ };
1862
+ }
1863
+ return {
1864
+ index,
1865
+ success: true,
1866
+ dirId: result.data?.dirId
1867
+ };
1868
+ } catch (error) {
1869
+ return {
1870
+ index,
1871
+ success: false,
1872
+ error: error.message || "Unknown error"
1873
+ };
1874
+ }
1875
+ });
1876
+ const createResults = await Promise.all(createPromises);
1877
+ results.push(...createResults);
1878
+ const successResults = results.filter((r) => r.success);
1879
+ const failureResults = results.filter((r) => !r.success);
1880
+ const successText = successResults.length > 0 ? `\u2705 **Successfully created ${successResults.length} browsers**
1881
+
1882
+ ${successResults.map(
1883
+ (r) => ` - #${r.index + 1}${r.dirId ? ` (ID: \`${r.dirId}\`)` : ""}`
1884
+ ).join("\n")}` : "";
1885
+ const failureText = failureResults.length > 0 ? `\u274C **Failed to create ${failureResults.length} browsers:**
1886
+
1887
+ ${failureResults.map(
1888
+ (r) => ` - #${r.index + 1}: ${r.error}`
1889
+ ).join("\n")}` : "";
1890
+ const summaryLines = [
1891
+ `**Total Requests:** ${results.length}`,
1892
+ `**Success:** ${successResults.length}`,
1893
+ `**Failed:** ${failureResults.length}`,
1894
+ "",
1895
+ ...[successText, failureText].filter(Boolean)
1896
+ ];
1897
+ const summaryText = summaryLines.join("\n");
1898
+ return {
1899
+ content: [
1900
+ {
1901
+ type: "text",
1902
+ text: summaryText
1903
+ }
1904
+ ]
1905
+ };
1906
+ }
1907
+ };
1908
+ var batchCreateBrowsers = new BatchCreateBrowsers();
1909
+ var UpdateBrowser = class {
1910
+ name = "roxy_update_browser";
1911
+ description = "Update a browser with complete configuration control - for expert users needing full parameter access";
1912
+ inputSchema = {
1913
+ type: "object",
1914
+ properties: {
1915
+ ...createBrowser.inputSchema.properties
1916
+ },
1917
+ required: ["workspaceId", "dirId"]
1918
+ };
1919
+ get schema() {
1920
+ return {
1921
+ name: this.name,
1922
+ description: this.description,
1923
+ inputSchema: this.inputSchema
1924
+ };
1925
+ }
1926
+ async handle(params) {
1927
+ const result = await request("/browser/mdf", {
1928
+ method: "POST",
1929
+ body: JSON.stringify(params)
1930
+ });
1931
+ let text = "";
1932
+ if (result.code !== 0) {
1933
+ text = `\u274C **Failed to update browser:**
1934
+
1935
+ error message: ${result.msg}`;
1936
+ } else {
1937
+ text = "\u2705 **Browser Updated Successfully**";
1938
+ }
1939
+ return {
1940
+ content: [
1941
+ {
1942
+ type: "text",
1943
+ text
1944
+ }
1945
+ ]
1946
+ };
1947
+ }
1948
+ };
1949
+ var OpenBrowser = class {
1950
+ name = "roxy_open_browsers";
1951
+ description = "Open one or multiple browsers and return their CDP WebSocket endpoints for automation";
1952
+ inputSchema = {
1953
+ type: "object",
1954
+ properties: {
1955
+ workspaceId: {
1956
+ type: "number",
1957
+ description: "Workspace ID"
1958
+ },
1959
+ dirIds: {
1960
+ type: "array",
1961
+ items: { type: "string" },
1962
+ description: "Array of browser directory IDs to open"
1963
+ },
1964
+ forceOpen: {
1965
+ type: "boolean",
1966
+ // 即使浏览器已被其他用户打开,还是强制打开
1967
+ description: "Force open browser even if it is already opened by other users (default: true)",
1968
+ default: true
1969
+ },
1970
+ args: {
1971
+ type: "array",
1972
+ items: { type: "string" },
1973
+ description: "Optional browser startup arguments (--headless=new startup headless)"
1974
+ }
1975
+ },
1976
+ required: ["workspaceId", "dirIds"]
1977
+ };
1978
+ get schema() {
1979
+ return {
1980
+ name: this.name,
1981
+ description: this.description,
1982
+ inputSchema: this.inputSchema
1983
+ };
1984
+ }
1985
+ async handle(params) {
1986
+ const { workspaceId, dirIds, forceOpen = true, args } = params;
1987
+ if (!workspaceId || !Array.isArray(dirIds) || dirIds.length === 0) {
1988
+ return {
1989
+ content: [
1990
+ {
1991
+ type: "text",
1992
+ text: "\u274C **Failed to open browsers:**\n\n workspaceId and dirIds are required, and dirIds must not be empty"
1993
+ }
1994
+ ]
1995
+ };
1996
+ }
1997
+ const results = [];
1998
+ const openPromises = dirIds.map(async (dirId) => {
1999
+ try {
2000
+ const result = await request("/browser/open", {
2001
+ method: "POST",
2002
+ body: JSON.stringify({
2003
+ workspaceId,
2004
+ dirId,
2005
+ forceOpen,
2006
+ args
2007
+ })
2008
+ });
2009
+ if (result.code !== 0) {
2010
+ return {
2011
+ dirId,
2012
+ success: false,
2013
+ error: result.msg
2014
+ };
2015
+ }
2016
+ return {
2017
+ dirId,
2018
+ success: true,
2019
+ data: result.data
2020
+ };
2021
+ } catch (error) {
2022
+ return {
2023
+ dirId,
2024
+ success: false,
2025
+ error: error.message || "Unknown error"
2026
+ };
2027
+ }
2028
+ });
2029
+ const openResults = await Promise.all(openPromises);
2030
+ results.push(...openResults);
2031
+ const successResults = results.filter((r) => r.success);
2032
+ const failureResults = results.filter((r) => !r.success);
2033
+ const successText = successResults.length > 0 ? [
2034
+ `\u2705 **Successfully opened ${successResults.length} browser(s):**`,
2035
+ "",
2036
+ ...successResults.map((r) => {
2037
+ const data = r.data || {};
2038
+ return [
2039
+ `**Browser ${data.dirId || r.dirId || "Unknown"}** (PID:${data.pid ?? "Unknown"})`,
2040
+ ` - CDP WebSocket: \`${data.ws ?? "N/A"}\``,
2041
+ ` - HTTP Endpoint: \`${data.http ?? "N/A"}\``,
2042
+ ` - Core Version: ${data.coreVersion ?? "Unknown"}`
2043
+ ].join("\n");
2044
+ })
2045
+ ].join("\n") : "";
2046
+ const failureText = failureResults.length > 0 ? [
2047
+ `\u274C **Failed to open ${failureResults.length} browser(s):**`,
2048
+ "",
2049
+ ...failureResults.map(
2050
+ (r) => ` - ${r.dirId}: ${r.error}`
2051
+ )
2052
+ ].join("\n") : "";
2053
+ const summaryLines = [
2054
+ `**Workspace:** ${workspaceId}`,
2055
+ `**Total Requests:** ${results.length}`,
2056
+ `**Success:** ${successResults.length}`,
2057
+ `**Failed:** ${failureResults.length}`,
2058
+ "",
2059
+ ...[successText, failureText].filter(Boolean)
2060
+ ];
2061
+ const summaryText = summaryLines.join("\n");
2062
+ return {
2063
+ content: [
2064
+ {
2065
+ type: "text",
2066
+ text: summaryText
2067
+ }
2068
+ ]
2069
+ };
2070
+ }
2071
+ };
2072
+ var ListBrowsers = class {
2073
+ name = "roxy_list_browsers";
2074
+ description = "Get list of browsers in specified workspace/project";
2075
+ inputSchema = {
2076
+ type: "object",
2077
+ properties: {
2078
+ workspaceId: {
2079
+ type: "number",
2080
+ description: "Workspace ID"
2081
+ },
2082
+ projectIds: {
2083
+ type: "string",
2084
+ description: "Comma-separated project IDs"
2085
+ },
2086
+ windowName: {
2087
+ type: "string",
2088
+ description: "Filter by browser window name"
2089
+ },
2090
+ pageIndex: {
2091
+ type: "number",
2092
+ description: "Page index for pagination (default: 1)",
2093
+ default: 1
2094
+ },
2095
+ pageSize: {
2096
+ type: "number",
2097
+ description: "Number of items per page (default: 15)",
2098
+ default: 15
2099
+ }
2100
+ },
2101
+ required: ["workspaceId"]
2102
+ };
2103
+ get schema() {
2104
+ return {
2105
+ name: this.name,
2106
+ description: this.description,
2107
+ inputSchema: this.inputSchema
2108
+ };
2109
+ }
2110
+ async handle(params) {
2111
+ const searchParams = new URLSearchParams();
2112
+ searchParams.append("workspaceId", params.workspaceId.toString());
2113
+ if (params.projectIds)
2114
+ searchParams.append("projectIds", params.projectIds);
2115
+ if (params.windowName)
2116
+ searchParams.append("windowName", params.windowName);
2117
+ if (params.pageIndex)
2118
+ searchParams.append("page_index", params.pageIndex.toString());
2119
+ if (params.pageSize)
2120
+ searchParams.append("page_size", params.pageSize.toString());
2121
+ const result = await request(`/browser/list_v3?${searchParams}`, {
2122
+ method: "GET"
2123
+ });
2124
+ const data = result.data;
2125
+ let text = "";
2126
+ if (result.code !== 0) {
2127
+ text = `\u274C **Failed to list browsers:**
2128
+
2129
+ error message: ${result.msg}`;
2130
+ } else {
2131
+ text = `Found ${data.total} browsers in workspace ${params.workspaceId}:
2132
+
2133
+ ${data.rows.map(
2134
+ (browser) => `**${browser.windowName || "Unnamed"}** (ID: ${browser.dirId})
2135
+ - Project: ${browser.projectId}
2136
+ - Sort: ${browser.sortNum}
2137
+ - OS: ${browser.os}
2138
+ - Status: ${browser.status}`
2139
+ ).join("\n\n")}`;
2140
+ }
2141
+ return {
2142
+ content: [
2143
+ {
2144
+ type: "text",
2145
+ text
2146
+ }
2147
+ ]
2148
+ };
2149
+ }
2150
+ };
2151
+ var CloseBrowsers = class {
2152
+ name = "roxy_close_browsers";
2153
+ description = "Close multiple browsers by their directory IDs";
2154
+ inputSchema = {
2155
+ type: "object",
2156
+ properties: {
2157
+ dirIds: {
2158
+ type: "array",
2159
+ items: { type: "string" },
2160
+ description: "Array of browser directory IDs to close"
2161
+ }
2162
+ },
2163
+ required: ["dirIds"]
2164
+ };
2165
+ get schema() {
2166
+ return {
2167
+ name: this.name,
2168
+ description: this.description,
2169
+ inputSchema: this.inputSchema
2170
+ };
2171
+ }
2172
+ async handle(params) {
2173
+ if (!params.dirIds || params.dirIds.length === 0) {
2174
+ return {
2175
+ content: [
2176
+ {
2177
+ type: "text",
2178
+ text: "\u274C **Failed to close browsers:**\n\n dirIds are required"
2179
+ }
2180
+ ]
2181
+ };
2182
+ }
2183
+ const results = [];
2184
+ const closePromises = params.dirIds.map(async (dirId) => {
2185
+ try {
2186
+ const result = await request("/browser/close", {
2187
+ method: "POST",
2188
+ body: JSON.stringify({ dirId })
2189
+ });
2190
+ if (result.code !== 0) {
2191
+ return { dirId, success: false, error: result.msg };
2192
+ }
2193
+ return { dirId, success: true };
2194
+ } catch (error) {
2195
+ return { dirId, success: false, error: error.message || "Unknown error" };
2196
+ }
2197
+ });
2198
+ const closeResults = await Promise.all(closePromises);
2199
+ results.push(...closeResults);
2200
+ const successCount = results.filter((r) => r.success).length;
2201
+ const failureCount = results.filter((r) => !r.success).length;
2202
+ const successText = successCount > 0 ? `\u2705 Successfully closed ${successCount} browsers` : "";
2203
+ const failureText = failureCount > 0 ? `\u274C Failed to close ${failureCount} browsers:
2204
+ ${results.filter((r) => !r.success).map(
2205
+ (r) => ` - ${r.dirId}: ${r.error}`
2206
+ ).join("\n")}` : "";
2207
+ return {
2208
+ content: [
2209
+ {
2210
+ type: "text",
2211
+ text: [successText, failureText].filter(Boolean).join("\n\n")
2212
+ }
2213
+ ]
2214
+ };
2215
+ }
2216
+ };
2217
+ var DeleteBrowsers = class {
2218
+ name = "roxy_delete_browsers";
2219
+ description = "Delete multiple browsers permanently by their directory IDs";
2220
+ inputSchema = {
2221
+ type: "object",
2222
+ properties: {
2223
+ workspaceId: {
2224
+ type: "number",
2225
+ description: "Workspace ID"
2226
+ },
2227
+ dirIds: {
2228
+ type: "array",
2229
+ items: { type: "string" },
2230
+ description: "Array of browser directory IDs to delete"
2231
+ }
2232
+ },
2233
+ required: ["workspaceId", "dirIds"]
2234
+ };
2235
+ get schema() {
2236
+ return {
2237
+ name: this.name,
2238
+ description: this.description,
2239
+ inputSchema: this.inputSchema
2240
+ };
2241
+ }
2242
+ async handle(params) {
2243
+ if (!params.workspaceId || !params.dirIds || params.dirIds.length === 0) {
2244
+ return {
2245
+ content: [
2246
+ {
2247
+ type: "text",
2248
+ text: "\u274C **Failed to delete browsers:**\n\n workspaceId and dirIds are required"
2249
+ }
2250
+ ]
2251
+ };
2252
+ }
2253
+ const result = await request("/browser/delete", {
2254
+ method: "POST",
2255
+ body: JSON.stringify({
2256
+ workspaceId: params.workspaceId,
2257
+ dirIds: params.dirIds,
2258
+ isSoftDelete: true
2259
+ })
2260
+ });
2261
+ let text = "";
2262
+ if (result.code !== 0) {
2263
+ text = `\u274C **Browser Deletion Failed**
2264
+
2265
+ **Error:** ${result.msg}
2266
+ **Workspace:** ${params.workspaceId}
2267
+ **Failed Browsers:** ${params.dirIds.length}
2268
+
2269
+ **Browser IDs:**
2270
+ ${params.dirIds.map((dirId, index) => ` ${index + 1}. \`${dirId}\``).join("\n")}`;
2271
+ } else {
2272
+ text = `\u2705 **Browsers Deleted Successfully**
2273
+
2274
+ **Count:** ${params.dirIds.length} browser(s)
2275
+ **Workspace:** ${params.workspaceId}
2276
+
2277
+ **Deleted Browsers:**
2278
+ ${params.dirIds.map((dirId, index) => ` ${index + 1}. \`${dirId}\``).join("\n")}`;
2279
+ }
2280
+ return {
2281
+ content: [
2282
+ {
2283
+ type: "text",
2284
+ text
2285
+ }
2286
+ ]
2287
+ };
2288
+ }
2289
+ };
2290
+ var GetBrowserDetail = class {
2291
+ name = "roxy_get_browser_detail";
2292
+ description = "Get detailed information for a specific browser window";
2293
+ inputSchema = {
2294
+ type: "object",
2295
+ properties: {
2296
+ workspaceId: {
2297
+ type: "number",
2298
+ description: "Workspace ID"
2299
+ },
2300
+ dirId: {
2301
+ type: "string",
2302
+ description: "Browser directory ID"
2303
+ }
2304
+ },
2305
+ required: ["workspaceId", "dirId"]
2306
+ };
2307
+ get schema() {
2308
+ return {
2309
+ name: this.name,
2310
+ description: this.description,
2311
+ inputSchema: this.inputSchema
2312
+ };
2313
+ }
2314
+ async handle(params) {
2315
+ if (!params.workspaceId || !params.dirId) {
2316
+ return {
2317
+ content: [
2318
+ {
2319
+ type: "text",
2320
+ text: "\u274C **Failed to get browser detail:**\n\n workspaceId and dirId are required"
2321
+ }
2322
+ ]
2323
+ };
2324
+ }
2325
+ const searchParams = new URLSearchParams();
2326
+ searchParams.append("workspaceId", params.workspaceId.toString());
2327
+ searchParams.append("dirId", params.dirId);
2328
+ const result = await request(`/browser/detail?${searchParams}`, {
2329
+ method: "GET"
2330
+ });
2331
+ let text = "";
2332
+ if (result.code !== 0) {
2333
+ text = `\u274C **Failed to get browser detail:**
2334
+
2335
+ error message: ${result.msg}`;
2336
+ } else {
2337
+ const detail = result.data.rows && result.data.rows.length > 0 ? result.data.rows[0] : null;
2338
+ if (!detail) {
2339
+ text = "\u274C **Browser not found or no data returned**";
2340
+ } else {
2341
+ const cookieCount = detail.cookie?.length || 0;
2342
+ const { cookie: _cookie, ...detailWithoutCookies } = detail;
2343
+ text = `**Browser Details Summary**
2344
+
2345
+ **ID:** \`${detail.dirId}\`
2346
+ **Name:** ${detail.windowName}
2347
+ **Sort Number:** ${detail.windowSortNum}
2348
+ **Project:** ${detail.projectName} (ID: ${detail.projectId})
2349
+ **OS:** ${detail.os} ${detail.osVersion}
2350
+ **Core Version:** ${detail.coreVersion}
2351
+ **Search Engine:** ${detail.searchEngine}
2352
+ **Open Status:** ${detail.openStatus ? "\u2705 Opened" : "\u274C Closed"}
2353
+ **Cookies:** ${cookieCount} stored (excluded from response to save tokens)
2354
+
2355
+ **Full Details (JSON):**
2356
+ \`\`\`json
2357
+ ${JSON.stringify(detailWithoutCookies, null, 2)}
2358
+ \`\`\``;
2359
+ }
2360
+ }
2361
+ return {
2362
+ content: [
2363
+ {
2364
+ type: "text",
2365
+ text
2366
+ }
2367
+ ]
2368
+ };
2369
+ }
2370
+ };
2371
+ var ClearLocalCache = class {
2372
+ name = "roxy_clear_local_cache";
2373
+ description = "Clear local cache for specified browsers";
2374
+ inputSchema = {
2375
+ type: "object",
2376
+ properties: {
2377
+ dirIds: {
2378
+ type: "array",
2379
+ items: { type: "string" },
2380
+ description: "Array of browser directory IDs"
2381
+ }
2382
+ },
2383
+ required: ["dirIds"]
2384
+ };
2385
+ get schema() {
2386
+ return {
2387
+ name: this.name,
2388
+ description: this.description,
2389
+ inputSchema: this.inputSchema
2390
+ };
2391
+ }
2392
+ async handle(params) {
2393
+ if (!params.dirIds || params.dirIds.length === 0) {
2394
+ return {
2395
+ content: [
2396
+ {
2397
+ type: "text",
2398
+ text: "\u274C **Failed to clear local cache:**\n\n dirIds are required"
2399
+ }
2400
+ ]
2401
+ };
2402
+ }
2403
+ const result = await request("/browser/clear_local_cache", {
2404
+ method: "POST",
2405
+ body: JSON.stringify({ dirIds: params.dirIds })
2406
+ });
2407
+ let text = "";
2408
+ if (result.code !== 0) {
2409
+ text = `\u274C **Failed to clear local cache:**
2410
+
2411
+ error message: ${result.msg}`;
2412
+ } else {
2413
+ text = `\u2705 **Local Cache Cleared**
2414
+
2415
+ **Browser Count:** ${params.dirIds.length}
2416
+
2417
+ **Browser IDs:**
2418
+ ${params.dirIds.map((id, index) => ` ${index + 1}. \`${id}\``).join("\n")}`;
2419
+ }
2420
+ return {
2421
+ content: [
2422
+ {
2423
+ type: "text",
2424
+ text
2425
+ }
2426
+ ]
2427
+ };
2428
+ }
2429
+ };
2430
+ var ClearServerCache = class {
2431
+ name = "roxy_clear_server_cache";
2432
+ description = "Clear server-side cache for specified browsers";
2433
+ inputSchema = {
2434
+ type: "object",
2435
+ properties: {
2436
+ workspaceId: {
2437
+ type: "number",
2438
+ description: "Workspace ID"
2439
+ },
2440
+ dirIds: {
2441
+ type: "array",
2442
+ items: { type: "string" },
2443
+ description: "Array of browser directory IDs"
2444
+ }
2445
+ },
2446
+ required: ["workspaceId", "dirIds"]
2447
+ };
2448
+ get schema() {
2449
+ return {
2450
+ name: this.name,
2451
+ description: this.description,
2452
+ inputSchema: this.inputSchema
2453
+ };
2454
+ }
2455
+ async handle(params) {
2456
+ if (!params.workspaceId || !params.dirIds || params.dirIds.length === 0) {
2457
+ return {
2458
+ content: [
2459
+ {
2460
+ type: "text",
2461
+ text: "\u274C **Failed to clear server cache:**\n\n workspaceId and dirIds are required"
2462
+ }
2463
+ ]
2464
+ };
2465
+ }
2466
+ const result = await request("/browser/clear_server_cache", {
2467
+ method: "POST",
2468
+ body: JSON.stringify({
2469
+ workspaceId: params.workspaceId,
2470
+ dirIds: params.dirIds
2471
+ })
2472
+ });
2473
+ let text = "";
2474
+ if (result.code !== 0) {
2475
+ text = `\u274C **Failed to clear server cache:**
2476
+
2477
+ error message: ${result.msg}`;
2478
+ } else {
2479
+ text = `\u2705 **Server Cache Cleared**
2480
+
2481
+ **Workspace:** ${params.workspaceId}
2482
+ **Browser Count:** ${params.dirIds.length}
2483
+
2484
+ **Browser IDs:**
2485
+ ${params.dirIds.map((id, index) => ` ${index + 1}. \`${id}\``).join("\n")}`;
2486
+ }
2487
+ return {
2488
+ content: [
2489
+ {
2490
+ type: "text",
2491
+ text
2492
+ }
2493
+ ]
2494
+ };
2495
+ }
2496
+ };
2497
+ var RandomFingerprint = class {
2498
+ name = "roxy_random_fingerprint";
2499
+ description = "Randomize browser fingerprint for a specific browser";
2500
+ inputSchema = {
2501
+ type: "object",
2502
+ properties: {
2503
+ workspaceId: {
2504
+ type: "number",
2505
+ description: "Workspace ID"
2506
+ },
2507
+ dirId: {
2508
+ type: "string",
2509
+ description: "Browser directory ID"
2510
+ }
2511
+ },
2512
+ required: ["workspaceId", "dirId"]
2513
+ };
2514
+ get schema() {
2515
+ return {
2516
+ name: this.name,
2517
+ description: this.description,
2518
+ inputSchema: this.inputSchema
2519
+ };
2520
+ }
2521
+ async handle(params) {
2522
+ if (!params.workspaceId || !params.dirId) {
2523
+ return {
2524
+ content: [
2525
+ {
2526
+ type: "text",
2527
+ text: "\u274C **Failed to randomize fingerprint:**\n\n workspaceId and dirId are required"
2528
+ }
2529
+ ]
2530
+ };
2531
+ }
2532
+ const result = await request("/browser/random_env", {
2533
+ method: "POST",
2534
+ body: JSON.stringify({
2535
+ workspaceId: params.workspaceId,
2536
+ dirId: params.dirId
2537
+ })
2538
+ });
2539
+ let text = "";
2540
+ if (result.code !== 0) {
2541
+ text = `\u274C **Failed to randomize fingerprint:**
2542
+
2543
+ error message: ${result.msg}`;
2544
+ } else {
2545
+ text = `\u2705 **Browser Fingerprint Randomized**
2546
+
2547
+ **Browser ID:** \`${params.dirId}\`
2548
+ **Workspace:** ${params.workspaceId}
2549
+
2550
+ *Browser fingerprint has been randomized. Restart the browser to apply changes.*`;
2551
+ }
2552
+ return {
2553
+ content: [
2554
+ {
2555
+ type: "text",
2556
+ text
2557
+ }
2558
+ ]
2559
+ };
2560
+ }
2561
+ };
2562
+ var ListLabels = class {
2563
+ name = "roxy_list_labels";
2564
+ description = "Get list of labels in specified workspace";
2565
+ inputSchema = {
2566
+ type: "object",
2567
+ properties: {
2568
+ workspaceId: {
2569
+ type: "number",
2570
+ description: "Workspace ID"
2571
+ }
2572
+ },
2573
+ required: ["workspaceId"]
2574
+ };
2575
+ get schema() {
2576
+ return {
2577
+ name: this.name,
2578
+ description: this.description,
2579
+ inputSchema: this.inputSchema
2580
+ };
2581
+ }
2582
+ async handle(params) {
2583
+ if (!params.workspaceId) {
2584
+ return {
2585
+ content: [
2586
+ {
2587
+ type: "text",
2588
+ text: "\u274C **Failed to list labels:**\n\n workspaceId is required"
2589
+ }
2590
+ ]
2591
+ };
2592
+ }
2593
+ const searchParams = new URLSearchParams();
2594
+ searchParams.append("workspaceId", params.workspaceId.toString());
2595
+ const result = await request(`/browser/label?${searchParams}`, {
2596
+ method: "GET"
2597
+ });
2598
+ let text = "";
2599
+ if (result.code !== 0) {
2600
+ text = `\u274C **Failed to list labels:**
2601
+
2602
+ error message: ${result.msg}`;
2603
+ } else {
2604
+ const labels = result.data || [];
2605
+ text = `Found ${labels.length} labels in workspace ${params.workspaceId}:
2606
+
2607
+ ${labels.map(
2608
+ (label) => `**${label.name}** (ID: ${label.id})
2609
+ - Color: ${label.color}`
2610
+ ).join("\n\n")}`;
2611
+ }
2612
+ return {
2613
+ content: [
2614
+ {
2615
+ type: "text",
2616
+ text
2617
+ }
2618
+ ]
2619
+ };
2620
+ }
2621
+ };
2622
+ var GetConnectionInfo = class {
2623
+ name = "roxy_get_connection_info";
2624
+ description = "Get connection information (CDP endpoints, PIDs) for currently opened browsers";
2625
+ inputSchema = {
2626
+ type: "object",
2627
+ properties: {
2628
+ dirIds: {
2629
+ type: "array",
2630
+ items: { type: "string" },
2631
+ description: "Array of browser directory IDs to query (optional, returns all if not specified)"
2632
+ }
2633
+ }
2634
+ };
2635
+ get schema() {
2636
+ return {
2637
+ name: this.name,
2638
+ description: this.description,
2639
+ inputSchema: this.inputSchema
2640
+ };
2641
+ }
2642
+ async handle(params) {
2643
+ const searchParams = new URLSearchParams();
2644
+ if (params.dirIds && params.dirIds.length > 0) {
2645
+ searchParams.append("dirIds", params.dirIds.join(","));
2646
+ }
2647
+ const queryString = searchParams.toString();
2648
+ const endpoint = queryString ? `/browser/connection_info?${queryString}` : "/browser/connection_info";
2649
+ const result = await request(endpoint, {
2650
+ method: "GET"
2651
+ });
2652
+ let text = "";
2653
+ if (result.code !== 0) {
2654
+ text = `\u274C **Failed to get connection info:**
2655
+
2656
+ error message: ${result.msg}`;
2657
+ } else {
2658
+ const connections = result.data || [];
2659
+ if (connections.length === 0) {
2660
+ text = "\u26A0\uFE0F No opened browsers found.\n\nUse `roxy_open_browsers` to open browsers first.";
2661
+ } else {
2662
+ text = `Found ${connections.length} opened browser(s):
2663
+
2664
+ ${connections.map(
2665
+ (conn) => `**${conn.windowName || "Unnamed"}** (${conn.dirId})
2666
+ - PID: ${conn.pid}
2667
+ - CDP WebSocket: \`${conn.ws}\`
2668
+ - HTTP Endpoint: \`${conn.http}\`
2669
+ - Core Version: ${conn.coreVersion}
2670
+ - Driver: ${conn.driver}`
2671
+ ).join("\n\n")}`;
2672
+ }
2673
+ }
2674
+ return {
2675
+ content: [
2676
+ {
2677
+ type: "text",
2678
+ text
2679
+ }
2680
+ ]
2681
+ };
2682
+ }
2683
+ };
2684
+ var openBrowser = new OpenBrowser();
2685
+ var updateBrowser = new UpdateBrowser();
2686
+ var listBrowsers = new ListBrowsers();
2687
+ var closeBrowsers = new CloseBrowsers();
2688
+ var deleteBrowsers = new DeleteBrowsers();
2689
+ var getBrowserDetail = new GetBrowserDetail();
2690
+ var clearLocalCache = new ClearLocalCache();
2691
+ var clearServerCache = new ClearServerCache();
2692
+ var randomFingerprint = new RandomFingerprint();
2693
+ var listLabels = new ListLabels();
2694
+ var getConnectionInfo = new GetConnectionInfo();
2695
+
2696
+ // src/modules/other.ts
2697
+ var ListWorkspaces = class {
2698
+ name = "roxy_list_workspaces";
2699
+ description = "Get list of all workspaces and their projects from RoxyBrowser";
2700
+ inputSchema = {
2701
+ type: "object",
2702
+ properties: {
2703
+ pageIndex: {
2704
+ type: "number",
2705
+ description: "Page index for pagination (default: 1)",
2706
+ default: 1
2707
+ },
2708
+ pageSize: {
2709
+ type: "number",
2710
+ description: "Number of items per page (default: 15)",
2711
+ default: 15
2712
+ }
2713
+ }
2714
+ };
2715
+ get schema() {
2716
+ return {
2717
+ name: this.name,
2718
+ description: this.description,
2719
+ inputSchema: this.inputSchema
2720
+ };
2721
+ }
2722
+ async handle(params) {
2723
+ const { pageIndex = 1, pageSize = 15 } = params || {};
2724
+ const searchParams = new URLSearchParams();
2725
+ searchParams.append("page_index", pageIndex.toString());
2726
+ searchParams.append("page_size", pageSize.toString());
2727
+ const result = await request(`/browser/workspace?${searchParams}`, {
2728
+ method: "GET"
2729
+ });
2730
+ let text = "";
2731
+ if (result.code !== 0) {
2732
+ text = `\u274C **Failed to list workspaces:**
2733
+
2734
+ error message: ${result.msg}`;
2735
+ } else {
2736
+ const data = result.data;
2737
+ text = `Found ${data.total} workspaces:
2738
+
2739
+ ${data.rows.map(
2740
+ (ws) => `**${ws.workspaceName}** (ID: ${ws.id})
2741
+ ${ws.project_details.map(
2742
+ (proj) => ` - ${proj.projectName} (ID: ${proj.projectId})`
2743
+ ).join("\n")}`
2744
+ ).join("\n\n")}`;
2745
+ }
2746
+ return {
2747
+ content: [
2748
+ {
2749
+ type: "text",
2750
+ text
2751
+ }
2752
+ ]
2753
+ };
2754
+ }
2755
+ };
2756
+ var HealthCheck = class {
2757
+ name = "roxy_health_check";
2758
+ description = "Check if the target server is alive and healthy. This tool performs a health check to verify server connectivity and status.";
2759
+ inputSchema = {
2760
+ type: "object",
2761
+ properties: {
2762
+ includeWorkspaceCheck: {
2763
+ type: "boolean",
2764
+ description: "Include workspace connectivity tests (optional, default: true)",
2765
+ default: true
2766
+ },
2767
+ includeBrowserCheck: {
2768
+ type: "boolean",
2769
+ description: "Include browser availability checks (optional, default: true)",
2770
+ default: true
2771
+ },
2772
+ verbose: {
2773
+ type: "boolean",
2774
+ description: "Include detailed diagnostic information (optional, default: false)",
2775
+ default: false
2776
+ }
2777
+ }
2778
+ };
2779
+ get schema() {
2780
+ return {
2781
+ name: this.name,
2782
+ description: this.description,
2783
+ inputSchema: this.inputSchema
2784
+ };
2785
+ }
2786
+ async handle(params) {
2787
+ const { includeWorkspaceCheck = true, includeBrowserCheck = true, verbose = false } = params || {};
2788
+ let healthStatus = "unknown";
2789
+ let healthError = "";
2790
+ try {
2791
+ const healthResult = await request("/health", {
2792
+ method: "GET"
2793
+ });
2794
+ if (healthResult.code === 0 || healthResult.code === void 0) {
2795
+ healthStatus = "healthy";
2796
+ } else {
2797
+ healthStatus = "unhealthy";
2798
+ healthError = healthResult.msg || "Health check failed";
2799
+ }
2800
+ } catch (error) {
2801
+ healthStatus = "unhealthy";
2802
+ healthError = error.message || "Failed to connect to server";
2803
+ }
2804
+ let text = `## \u{1F50D} \u5065\u5EB7\u68C0\u67E5\u62A5\u544A / Health Check Report
2805
+
2806
+ `;
2807
+ text += `### \u{1F310} \u670D\u52A1\u5668\u72B6\u6001 / Server Status
2808
+ `;
2809
+ text += `- **\u670D\u52A1\u5668\u8FDE\u63A5 / Server Connection**: ${healthStatus === "healthy" ? "\u2705 \u6B63\u5E38" : "\u274C \u5F02\u5E38"}
2810
+ `;
2811
+ if (healthStatus !== "healthy" && healthError) {
2812
+ text += `- **\u9519\u8BEF\u4FE1\u606F / Error**: ${healthError}
2813
+ `;
2814
+ }
2815
+ if (includeWorkspaceCheck && healthStatus === "healthy") {
2816
+ try {
2817
+ const workspaceResult = await request("/browser/workspace?page_index=1&page_size=5", {
2818
+ method: "GET"
2819
+ });
2820
+ if (workspaceResult.code === 0) {
2821
+ const workspaces = workspaceResult.data;
2822
+ text += `
2823
+ ### \u{1F4C1} \u5DE5\u4F5C\u533A\u4FE1\u606F / Workspace Information
2824
+ `;
2825
+ text += `- **\u53EF\u7528\u5DE5\u4F5C\u533A / Available Workspaces**: ${workspaces.total}
2826
+ `;
2827
+ if (workspaces.rows && workspaces.rows.length > 0) {
2828
+ text += `- **\u5DE5\u4F5C\u533A\u8BE6\u60C5 / Workspace Details**:
2829
+ `;
2830
+ workspaces.rows.slice(0, 3).forEach((ws) => {
2831
+ const projectCount = ws.project_details?.length || 0;
2832
+ text += ` - ${ws.workspaceName} (ID: ${ws.id}) - ${projectCount} projects
2833
+ `;
2834
+ });
2835
+ if (workspaces.total > 3) {
2836
+ text += ` - ... and ${workspaces.total - 3} more
2837
+ `;
142
2838
  }
2839
+ }
2840
+ } else {
2841
+ text += `
2842
+ ### \u{1F4C1} \u5DE5\u4F5C\u533A\u4FE1\u606F / Workspace Information
2843
+ `;
2844
+ text += `- **\u72B6\u6001**: \u26A0\uFE0F \u65E0\u6CD5\u83B7\u53D6\u5DE5\u4F5C\u533A\u4FE1\u606F
2845
+ `;
2846
+ text += `- **\u9519\u8BEF**: ${workspaceResult.msg}
2847
+ `;
2848
+ }
2849
+ } catch (error) {
2850
+ text += `
2851
+ ### \u{1F4C1} \u5DE5\u4F5C\u533A\u4FE1\u606F / Workspace Information
2852
+ `;
2853
+ text += `- **\u72B6\u6001**: \u274C \u65E0\u6CD5\u83B7\u53D6\u5DE5\u4F5C\u533A\u4FE1\u606F
2854
+ `;
2855
+ text += `- **\u9519\u8BEF**: ${error.message || "Unknown error"}
2856
+ `;
2857
+ }
2858
+ }
2859
+ if (includeBrowserCheck && healthStatus === "healthy") {
2860
+ try {
2861
+ const workspaceResult = await request("/browser/workspace?page_index=1&page_size=1", {
2862
+ method: "GET"
143
2863
  });
2864
+ if (workspaceResult.code === 0 && workspaceResult.data.rows && workspaceResult.data.rows.length > 0) {
2865
+ const firstWorkspace = workspaceResult.data.rows[0];
2866
+ const browserResult = await request(`/browser/list_v3?workspaceId=${firstWorkspace.id}&page_index=1&page_size=5`, {
2867
+ method: "GET"
2868
+ });
2869
+ if (browserResult.code === 0) {
2870
+ const browsers = browserResult.data;
2871
+ text += `
2872
+ ### \u{1F310} \u6D4F\u89C8\u5668\u4FE1\u606F / Browser Information
2873
+ `;
2874
+ text += `- **\u5DE5\u4F5C\u533A / Workspace**: ${firstWorkspace.workspaceName} (ID: ${firstWorkspace.id})
2875
+ `;
2876
+ text += `- **\u6D4F\u89C8\u5668\u603B\u6570 / Total Browsers**: ${browsers.total}
2877
+ `;
2878
+ if (browsers.rows && browsers.rows.length > 0) {
2879
+ text += `- **\u6D4F\u89C8\u5668\u793A\u4F8B / Browser Examples**:
2880
+ `;
2881
+ browsers.rows.slice(0, 3).forEach((browser) => {
2882
+ text += ` - ${browser.windowName || "Unnamed"} (ID: ${browser.dirId}) - ${browser.status}
2883
+ `;
2884
+ });
2885
+ }
2886
+ }
2887
+ }
2888
+ } catch (error) {
2889
+ text += `
2890
+ ### \u{1F310} \u6D4F\u89C8\u5668\u4FE1\u606F / Browser Information
2891
+ `;
2892
+ text += `- **\u72B6\u6001**: \u26A0\uFE0F \u65E0\u6CD5\u83B7\u53D6\u6D4F\u89C8\u5668\u4FE1\u606F
2893
+ `;
2894
+ text += `- **\u9519\u8BEF**: ${error.message || "Unknown error"}
2895
+ `;
2896
+ }
144
2897
  }
145
- async run() {
146
- console.error('🚀 Starting RoxyBrowser MCP Server...');
147
- const transport = new StdioServerTransport();
148
- await this.server.connect(transport);
149
- console.error('✅ RoxyBrowser MCP Server is running');
2898
+ if (verbose && healthStatus === "healthy") {
2899
+ text += `
2900
+ ### \u{1F4CA} \u8BE6\u7EC6\u4FE1\u606F / Detailed Information
2901
+ `;
2902
+ text += `- **\u5065\u5EB7\u68C0\u67E5\u65F6\u95F4 / Check Time**: ${(/* @__PURE__ */ new Date()).toISOString()}
2903
+ `;
2904
+ text += `- **\u68C0\u67E5\u6A21\u5F0F / Check Mode**: ${includeWorkspaceCheck ? "Workspace + " : ""}${includeBrowserCheck ? "Browser" : ""}
2905
+ `;
150
2906
  }
2907
+ return {
2908
+ content: [
2909
+ {
2910
+ type: "text",
2911
+ text
2912
+ }
2913
+ ]
2914
+ };
2915
+ }
2916
+ };
2917
+ var listWorkspaces = new ListWorkspaces();
2918
+ var healthCheck = new HealthCheck();
2919
+
2920
+ // src/index.ts
2921
+ var TOOLS = [
2922
+ listBrowsers.schema,
2923
+ batchCreateBrowsers.schema,
2924
+ createBrowser.schema,
2925
+ openBrowser.schema,
2926
+ updateBrowser.schema,
2927
+ closeBrowsers.schema,
2928
+ deleteBrowsers.schema,
2929
+ getBrowserDetail.schema,
2930
+ clearLocalCache.schema,
2931
+ clearServerCache.schema,
2932
+ randomFingerprint.schema,
2933
+ listLabels.schema,
2934
+ getConnectionInfo.schema,
2935
+ proxyList.schema,
2936
+ proxyStore.schema,
2937
+ createProxy.schema,
2938
+ batchCreateProxies.schema,
2939
+ detectProxy.schema,
2940
+ modifyProxy.schema,
2941
+ deleteProxies.schema,
2942
+ // getDetectChannels.schema,
2943
+ listAccounts.schema,
2944
+ createAccount.schema,
2945
+ batchCreateAccounts.schema,
2946
+ modifyAccount.schema,
2947
+ deleteAccounts.schema,
2948
+ listWorkspaces.schema,
2949
+ healthCheck.schema
2950
+ ];
2951
+ var RoxyBrowserMCPServer = class {
2952
+ server;
2953
+ constructor() {
2954
+ this.server = new Server(
2955
+ {
2956
+ name: "roxybrowser-openapi-mcp",
2957
+ version: "1.0.0"
2958
+ },
2959
+ {
2960
+ capabilities: {
2961
+ tools: {}
2962
+ }
2963
+ }
2964
+ );
2965
+ this.setupHandlers();
2966
+ }
2967
+ setupHandlers() {
2968
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
2969
+ tools: TOOLS
2970
+ }));
2971
+ this.server.setRequestHandler(CallToolRequestSchema, async (request2) => {
2972
+ const { name, arguments: args } = request2.params;
2973
+ try {
2974
+ switch (name) {
2975
+ // 浏览器相关
2976
+ case listBrowsers.name:
2977
+ return await listBrowsers.handle(args);
2978
+ case createBrowser.name:
2979
+ return await createBrowser.handle(args);
2980
+ case openBrowser.name:
2981
+ return await openBrowser.handle(args);
2982
+ case updateBrowser.name:
2983
+ return await updateBrowser.handle(args);
2984
+ case closeBrowsers.name:
2985
+ return await closeBrowsers.handle(args);
2986
+ case deleteBrowsers.name:
2987
+ return await deleteBrowsers.handle(args);
2988
+ case batchCreateBrowsers.name:
2989
+ return await batchCreateBrowsers.handle(args);
2990
+ case listLabels.name:
2991
+ return await listLabels.handle(args);
2992
+ case getConnectionInfo.name:
2993
+ return await getConnectionInfo.handle(args);
2994
+ case randomFingerprint.name:
2995
+ return await randomFingerprint.handle(args);
2996
+ case clearLocalCache.name:
2997
+ return await clearLocalCache.handle(args);
2998
+ case clearServerCache.name:
2999
+ return await clearServerCache.handle(args);
3000
+ case getBrowserDetail.name:
3001
+ return await getBrowserDetail.handle(args);
3002
+ // 账号相关
3003
+ case listAccounts.name:
3004
+ return await listAccounts.handle(args);
3005
+ case createAccount.name:
3006
+ return await createAccount.handle(args);
3007
+ case batchCreateAccounts.name:
3008
+ return await batchCreateAccounts.handle(args);
3009
+ case modifyAccount.name:
3010
+ return await modifyAccount.handle(args);
3011
+ case deleteAccounts.name:
3012
+ return await deleteAccounts.handle(args);
3013
+ // 代理相关
3014
+ case proxyList.name:
3015
+ return await proxyList.handle(args);
3016
+ case proxyStore.name:
3017
+ return await proxyStore.handle(args);
3018
+ case createProxy.name:
3019
+ return await createProxy.handle(args);
3020
+ case batchCreateProxies.name:
3021
+ return await batchCreateProxies.handle(args);
3022
+ case detectProxy.name:
3023
+ return await detectProxy.handle(args);
3024
+ case modifyProxy.name:
3025
+ return await modifyProxy.handle(args);
3026
+ case deleteProxies.name:
3027
+ return await deleteProxies.handle(args);
3028
+ // 空间列表
3029
+ case listWorkspaces.name:
3030
+ return await listWorkspaces.handle(args);
3031
+ // 健康检查
3032
+ case healthCheck.name:
3033
+ return await healthCheck.handle(args);
3034
+ default:
3035
+ throw new Error(`Unknown tool: ${name}`);
3036
+ }
3037
+ } catch (error) {
3038
+ return {
3039
+ content: [
3040
+ {
3041
+ type: "text",
3042
+ text: error instanceof Error ? error.message : "Unknown error"
3043
+ }
3044
+ ]
3045
+ };
3046
+ }
3047
+ });
3048
+ }
3049
+ async run() {
3050
+ console.error("\u{1F680} Starting RoxyBrowser MCP Server...");
3051
+ const transport = new StdioServerTransport();
3052
+ await this.server.connect(transport);
3053
+ console.error("\u2705 RoxyBrowser MCP Server is running");
3054
+ }
3055
+ };
3056
+ async function runServer() {
3057
+ const server = new RoxyBrowserMCPServer();
3058
+ await server.run();
151
3059
  }
152
- // ========== Programmatic API ==========
153
- /**
154
- * Create and run MCP server with stdio transport (for in-process usage).
155
- * Use when embedding the server in your own Node process.
156
- */
157
- export async function runServer() {
158
- const server = new RoxyBrowserMCPServer();
159
- await server.run();
160
- }
161
- // ========== Library exports for secondary development ==========
162
- export { listBrowsers, batchCreateBrowsers, createBrowser, openBrowser, updateBrowser, closeBrowsers, deleteBrowsers, getBrowserDetail, clearLocalCache, clearServerCache, randomFingerprint, listLabels, getConnectionInfo, } from './modules/browser.js';
163
- export { proxyList, proxyStore, createProxy, batchCreateProxies, detectProxy, modifyProxy, deleteProxies, } from './modules/proxy.js';
164
- export { listAccounts, createAccount, batchCreateAccounts, modifyAccount, deleteAccounts, } from './modules/account.js';
165
- export { listWorkspaces, healthCheck } from './modules/other.js';
166
- export { request, resolveConfig, DEFAULT_CONFIG } from './utils/index.js';
3060
+
3061
+ export { DEFAULT_CONFIG, RoxyBrowserMCPServer, TOOLS, batchCreateAccounts, batchCreateBrowsers, batchCreateProxies, clearLocalCache, clearServerCache, closeBrowsers, createAccount, createBrowser, createProxy, deleteAccounts, deleteBrowsers, deleteProxies, detectProxy, getBrowserDetail, getConnectionInfo, healthCheck, listAccounts, listBrowsers, listLabels, listWorkspaces, modifyAccount, modifyProxy, openBrowser, proxyList, proxyStore, randomFingerprint, request, resolveConfig, runServer, updateBrowser };
3062
+ //# sourceMappingURL=index.js.map
167
3063
  //# sourceMappingURL=index.js.map