@roxybrowser/openapi 1.0.4-beta.0 → 1.0.4-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -205
- package/lib/browser/browser-creator.d.ts.map +1 -1
- package/lib/browser/browser-creator.js +2 -1
- package/lib/browser/browser-creator.js.map +1 -1
- package/lib/index.js +266 -130
- package/lib/index.js.map +1 -1
- package/lib/roxy-client.d.ts +9 -1
- package/lib/roxy-client.d.ts.map +1 -1
- package/lib/roxy-client.js +31 -14
- package/lib/roxy-client.js.map +1 -1
- package/lib/types.d.ts +3 -0
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js +28 -7
- package/lib/types.js.map +1 -1
- package/lib/utils/error-analyzer.d.ts.map +1 -1
- package/lib/utils/error-analyzer.js +8 -1
- package/lib/utils/error-analyzer.js.map +1 -1
- package/package.json +2 -2
package/lib/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import { RoxyClient } from './roxy-client.js';
|
|
|
12
12
|
import { BrowserCreator } from './browser/browser-creator.js';
|
|
13
13
|
import { ProxyManager } from './proxy/proxy-manager.js';
|
|
14
14
|
import { ErrorAnalyzer } from './utils/error-analyzer.js';
|
|
15
|
-
import { ConfigError, BrowserCreationError, } from './types.js';
|
|
15
|
+
import { ConfigError, RoxyApiError, BrowserCreationError, LATEST_CORE_VERSION, } from './types.js';
|
|
16
16
|
// ========== Configuration ==========
|
|
17
17
|
function getConfig() {
|
|
18
18
|
const apiHost = process.env.ROXY_API_HOST || 'http://127.0.0.1:50000';
|
|
@@ -925,130 +925,214 @@ class RoxyBrowserMCPServer {
|
|
|
925
925
|
if (!params.workspaceId) {
|
|
926
926
|
throw new Error('workspaceId is required');
|
|
927
927
|
}
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
928
|
+
try {
|
|
929
|
+
// Build configuration from simple parameters
|
|
930
|
+
const config = BrowserCreator.buildSimpleConfig(params);
|
|
931
|
+
const finalConfig = BrowserCreator.applyDefaults(config);
|
|
932
|
+
// Validate configuration
|
|
933
|
+
const validation = BrowserCreator.validateConfig(finalConfig);
|
|
934
|
+
if (!validation.valid) {
|
|
935
|
+
throw new BrowserCreationError(`Configuration validation failed: ${validation.errors.join(', ')}`);
|
|
936
|
+
}
|
|
937
|
+
// Create browser
|
|
938
|
+
const result = await this.roxyClient.createBrowser(finalConfig);
|
|
939
|
+
const response = {
|
|
940
|
+
browser: {
|
|
941
|
+
dirId: result.dirId,
|
|
942
|
+
windowName: finalConfig.windowName || 'Simple Browser',
|
|
943
|
+
workspaceId: params.workspaceId,
|
|
944
|
+
projectId: params.projectId,
|
|
945
|
+
proxyConfigured: !!(params.proxyHost && params.proxyPort),
|
|
946
|
+
},
|
|
947
|
+
message: `Browser created successfully with ID: ${result.dirId}`,
|
|
948
|
+
};
|
|
949
|
+
return {
|
|
950
|
+
content: [
|
|
951
|
+
{
|
|
952
|
+
type: 'text',
|
|
953
|
+
text: `✅ **Simple Browser Created**\n\n` +
|
|
954
|
+
`**Browser ID:** \`${response.browser.dirId}\`\n` +
|
|
955
|
+
`**Name:** ${response.browser.windowName}\n` +
|
|
956
|
+
`**Workspace:** ${response.browser.workspaceId}\n` +
|
|
957
|
+
`${response.browser.projectId ? `**Project:** ${response.browser.projectId}\n` : ''}` +
|
|
958
|
+
`**Proxy:** ${response.browser.proxyConfigured ? '✅ Configured' : '❌ Not configured'}\n\n` +
|
|
959
|
+
`*Use this browser ID with \`roxy_open_browsers\` to start the browser and get CDP endpoints for automation.*`,
|
|
960
|
+
},
|
|
961
|
+
],
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
catch (error) {
|
|
965
|
+
// Check for quota error specifically
|
|
966
|
+
if (error instanceof RoxyApiError && error.code === 409 &&
|
|
967
|
+
error.message.includes('额度不足')) {
|
|
968
|
+
return {
|
|
969
|
+
content: [{
|
|
970
|
+
type: 'text',
|
|
971
|
+
text: `❌ **浏览器创建失败 - 窗口额度不足 / Browser Creation Failed - Insufficient Profiles Quota**\n\n` +
|
|
972
|
+
`**错误信息 / Error:** ${error.message}\n\n` +
|
|
973
|
+
`**解决步骤 / Solution Steps:**\n` +
|
|
974
|
+
`1. 打开 RoxyBrowser 应用 / Open RoxyBrowser app\n` +
|
|
975
|
+
`2. 前往费用中心 / Go to Billing Center\n` +
|
|
976
|
+
`3. 购买或升级窗口套餐 / Purchase or upgrade profiles plan\n` +
|
|
977
|
+
`4. 或者删除不需要的浏览器窗口以释放额度 / Or delete unused browser profiles to free up quota\n` +
|
|
978
|
+
`5. 等待生效后重试创建 / Retry creation after quota is available\n\n` +
|
|
979
|
+
`💡 **重要提示 / Important:** 必须使用 \`roxy_delete_browsers\` 删除浏览器才能释放额度,仅关闭浏览器无法释放额度。\n` +
|
|
980
|
+
`You must use \`roxy_delete_browsers\` to delete profiles to free up quota. Simply closing browsers will NOT free up quota.`,
|
|
981
|
+
}],
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
// Use enhanced error analysis for other errors
|
|
985
|
+
const formattedError = ErrorAnalyzer.formatErrorForDisplay(error instanceof Error ? error : new Error('Unknown error'));
|
|
986
|
+
return {
|
|
987
|
+
content: [{ type: 'text', text: formattedError }],
|
|
988
|
+
};
|
|
935
989
|
}
|
|
936
|
-
// Create browser
|
|
937
|
-
const result = await this.roxyClient.createBrowser(finalConfig);
|
|
938
|
-
const response = {
|
|
939
|
-
browser: {
|
|
940
|
-
dirId: result.dirId,
|
|
941
|
-
windowName: finalConfig.windowName || 'Simple Browser',
|
|
942
|
-
workspaceId: params.workspaceId,
|
|
943
|
-
projectId: params.projectId,
|
|
944
|
-
proxyConfigured: !!(params.proxyHost && params.proxyPort),
|
|
945
|
-
},
|
|
946
|
-
message: `Browser created successfully with ID: ${result.dirId}`,
|
|
947
|
-
};
|
|
948
|
-
return {
|
|
949
|
-
content: [
|
|
950
|
-
{
|
|
951
|
-
type: 'text',
|
|
952
|
-
text: `✅ **Simple Browser Created**\n\n` +
|
|
953
|
-
`**Browser ID:** \`${response.browser.dirId}\`\n` +
|
|
954
|
-
`**Name:** ${response.browser.windowName}\n` +
|
|
955
|
-
`**Workspace:** ${response.browser.workspaceId}\n` +
|
|
956
|
-
`${response.browser.projectId ? `**Project:** ${response.browser.projectId}\n` : ''}` +
|
|
957
|
-
`**Proxy:** ${response.browser.proxyConfigured ? '✅ Configured' : '❌ Not configured'}\n\n` +
|
|
958
|
-
`*Use this browser ID with \`roxy_open_browsers\` to start the browser and get CDP endpoints for automation.*`,
|
|
959
|
-
},
|
|
960
|
-
],
|
|
961
|
-
};
|
|
962
990
|
}
|
|
963
991
|
async handleCreateBrowserStandard(args) {
|
|
964
992
|
const params = args;
|
|
965
993
|
if (!params.workspaceId) {
|
|
966
994
|
throw new Error('workspaceId is required');
|
|
967
995
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
996
|
+
try {
|
|
997
|
+
// Build configuration from standard parameters
|
|
998
|
+
const config = BrowserCreator.buildStandardConfig(params);
|
|
999
|
+
const finalConfig = BrowserCreator.applyDefaults(config);
|
|
1000
|
+
// Validate configuration
|
|
1001
|
+
const validation = BrowserCreator.validateConfig(finalConfig);
|
|
1002
|
+
if (!validation.valid) {
|
|
1003
|
+
throw new BrowserCreationError(`Configuration validation failed: ${validation.errors.join(', ')}`);
|
|
1004
|
+
}
|
|
1005
|
+
// Create browser
|
|
1006
|
+
const result = await this.roxyClient.createBrowser(finalConfig);
|
|
1007
|
+
const response = {
|
|
1008
|
+
browser: {
|
|
1009
|
+
dirId: result.dirId,
|
|
1010
|
+
windowName: finalConfig.windowName || 'Standard Browser',
|
|
1011
|
+
workspaceId: params.workspaceId,
|
|
1012
|
+
projectId: params.projectId,
|
|
1013
|
+
os: finalConfig.os || 'Windows',
|
|
1014
|
+
coreVersion: finalConfig.coreVersion || LATEST_CORE_VERSION,
|
|
1015
|
+
proxyInfo: params.proxyInfo,
|
|
1016
|
+
windowSize: `${params.openWidth || '1000'}x${params.openHeight || '1000'}`,
|
|
1017
|
+
},
|
|
1018
|
+
message: `Standard browser created successfully with ID: ${result.dirId}`,
|
|
1019
|
+
};
|
|
1020
|
+
return {
|
|
1021
|
+
content: [
|
|
1022
|
+
{
|
|
1023
|
+
type: 'text',
|
|
1024
|
+
text: `✅ **Standard Browser Created**\n\n` +
|
|
1025
|
+
`**Browser ID:** \`${response.browser.dirId}\`\n` +
|
|
1026
|
+
`**Name:** ${response.browser.windowName}\n` +
|
|
1027
|
+
`**OS:** ${response.browser.os} ${finalConfig.osVersion || ''}\n` +
|
|
1028
|
+
`**Core Version:** ${response.browser.coreVersion}\n` +
|
|
1029
|
+
`**Window Size:** ${response.browser.windowSize}\n` +
|
|
1030
|
+
`**Workspace:** ${response.browser.workspaceId}\n` +
|
|
1031
|
+
`${response.browser.projectId ? `**Project:** ${response.browser.projectId}\n` : ''}` +
|
|
1032
|
+
`**Proxy:** ${response.browser.proxyInfo ? '✅ Configured' : '❌ Not configured'}\n\n` +
|
|
1033
|
+
`*Browser is ready for automation. Use \`roxy_open_browsers\` to start it.*`,
|
|
1034
|
+
},
|
|
1035
|
+
],
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
catch (error) {
|
|
1039
|
+
// Check for quota error specifically
|
|
1040
|
+
if (error instanceof RoxyApiError && error.code === 409 &&
|
|
1041
|
+
error.message.includes('额度不足')) {
|
|
1042
|
+
return {
|
|
1043
|
+
content: [{
|
|
1044
|
+
type: 'text',
|
|
1045
|
+
text: `❌ **浏览器创建失败 - 窗口额度不足 / Browser Creation Failed - Insufficient Profiles Quota**\n\n` +
|
|
1046
|
+
`**错误信息 / Error:** ${error.message}\n\n` +
|
|
1047
|
+
`**解决步骤 / Solution Steps:**\n` +
|
|
1048
|
+
`1. 打开 RoxyBrowser 应用 / Open RoxyBrowser app\n` +
|
|
1049
|
+
`2. 前往费用中心 / Go to Billing Center\n` +
|
|
1050
|
+
`3. 购买或升级窗口套餐 / Purchase or upgrade profiles plan\n` +
|
|
1051
|
+
`4. 或者删除不需要的浏览器窗口以释放额度 / Or delete unused browser profiles to free up quota\n` +
|
|
1052
|
+
`5. 等待生效后重试创建 / Retry creation after quota is available\n\n` +
|
|
1053
|
+
`💡 **重要提示 / Important:** 必须使用 \`roxy_delete_browsers\` 删除浏览器才能释放额度,仅关闭浏览器无法释放额度。\n` +
|
|
1054
|
+
`You must use \`roxy_delete_browsers\` to delete profiles to free up quota. Simply closing browsers will NOT free up quota.`,
|
|
1055
|
+
}],
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
// Use enhanced error analysis for other errors
|
|
1059
|
+
const formattedError = ErrorAnalyzer.formatErrorForDisplay(error instanceof Error ? error : new Error('Unknown error'));
|
|
1060
|
+
return {
|
|
1061
|
+
content: [{ type: 'text', text: formattedError }],
|
|
1062
|
+
};
|
|
975
1063
|
}
|
|
976
|
-
// Create browser
|
|
977
|
-
const result = await this.roxyClient.createBrowser(finalConfig);
|
|
978
|
-
const response = {
|
|
979
|
-
browser: {
|
|
980
|
-
dirId: result.dirId,
|
|
981
|
-
windowName: finalConfig.windowName || 'Standard Browser',
|
|
982
|
-
workspaceId: params.workspaceId,
|
|
983
|
-
projectId: params.projectId,
|
|
984
|
-
os: finalConfig.os || 'Windows',
|
|
985
|
-
coreVersion: finalConfig.coreVersion || '125',
|
|
986
|
-
proxyInfo: params.proxyInfo,
|
|
987
|
-
windowSize: `${params.openWidth || '1000'}x${params.openHeight || '1000'}`,
|
|
988
|
-
},
|
|
989
|
-
message: `Standard browser created successfully with ID: ${result.dirId}`,
|
|
990
|
-
};
|
|
991
|
-
return {
|
|
992
|
-
content: [
|
|
993
|
-
{
|
|
994
|
-
type: 'text',
|
|
995
|
-
text: `✅ **Standard Browser Created**\n\n` +
|
|
996
|
-
`**Browser ID:** \`${response.browser.dirId}\`\n` +
|
|
997
|
-
`**Name:** ${response.browser.windowName}\n` +
|
|
998
|
-
`**OS:** ${response.browser.os} ${finalConfig.osVersion || ''}\n` +
|
|
999
|
-
`**Core Version:** ${response.browser.coreVersion}\n` +
|
|
1000
|
-
`**Window Size:** ${response.browser.windowSize}\n` +
|
|
1001
|
-
`**Workspace:** ${response.browser.workspaceId}\n` +
|
|
1002
|
-
`${response.browser.projectId ? `**Project:** ${response.browser.projectId}\n` : ''}` +
|
|
1003
|
-
`**Proxy:** ${response.browser.proxyInfo ? '✅ Configured' : '❌ Not configured'}\n\n` +
|
|
1004
|
-
`*Browser is ready for automation. Use \`roxy_open_browsers\` to start it.*`,
|
|
1005
|
-
},
|
|
1006
|
-
],
|
|
1007
|
-
};
|
|
1008
1064
|
}
|
|
1009
1065
|
async handleCreateBrowserAdvanced(args) {
|
|
1010
1066
|
const params = args;
|
|
1011
1067
|
if (!params.workspaceId) {
|
|
1012
1068
|
throw new Error('workspaceId is required');
|
|
1013
1069
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
message: `Advanced browser created successfully with ID: ${result.dirId}`,
|
|
1030
|
-
};
|
|
1031
|
-
// Create detailed status text
|
|
1032
|
-
const configSummary = [
|
|
1033
|
-
`**Browser ID:** \`${response.browser.dirId}\``,
|
|
1034
|
-
`**Name:** ${finalConfig.windowName || 'Advanced Browser'}`,
|
|
1035
|
-
`**OS:** ${finalConfig.os || 'Windows'} ${finalConfig.osVersion || ''}`,
|
|
1036
|
-
`**Core Version:** ${finalConfig.coreVersion || '125'}`,
|
|
1037
|
-
finalConfig.userAgent ? `**User Agent:** ${finalConfig.userAgent.substring(0, 50)}...` : '',
|
|
1038
|
-
`**Search Engine:** ${finalConfig.searchEngine || 'Google'}`,
|
|
1039
|
-
finalConfig.proxyInfo?.proxyCategory !== 'noproxy' ? `**Proxy:** ✅ ${finalConfig.proxyInfo?.proxyCategory} ${finalConfig.proxyInfo?.host}:${finalConfig.proxyInfo?.port}` : '**Proxy:** ❌ No proxy',
|
|
1040
|
-
finalConfig.fingerInfo?.randomFingerprint ? '**Fingerprint:** 🎲 Random' : '**Fingerprint:** 🔒 Fixed',
|
|
1041
|
-
finalConfig.defaultOpenUrl?.length ? `**Default URLs:** ${finalConfig.defaultOpenUrl.length} URL(s)` : '',
|
|
1042
|
-
].filter(Boolean).join('\n');
|
|
1043
|
-
return {
|
|
1044
|
-
content: [
|
|
1045
|
-
{
|
|
1046
|
-
type: 'text',
|
|
1047
|
-
text: `✅ **Advanced Browser Created**\n\n${configSummary}\n\n` +
|
|
1048
|
-
`*Advanced browser configured with complete control. Use \`roxy_open_browsers\` to start it.*`,
|
|
1070
|
+
try {
|
|
1071
|
+
// Build configuration from advanced parameters
|
|
1072
|
+
const config = BrowserCreator.buildAdvancedConfig(params);
|
|
1073
|
+
const finalConfig = BrowserCreator.applyDefaults(config);
|
|
1074
|
+
// Validate configuration
|
|
1075
|
+
const validation = BrowserCreator.validateConfig(finalConfig);
|
|
1076
|
+
if (!validation.valid) {
|
|
1077
|
+
throw new BrowserCreationError(`Configuration validation failed: ${validation.errors.join(', ')}`);
|
|
1078
|
+
}
|
|
1079
|
+
// Create browser
|
|
1080
|
+
const result = await this.roxyClient.createBrowser(finalConfig);
|
|
1081
|
+
const response = {
|
|
1082
|
+
browser: {
|
|
1083
|
+
dirId: result.dirId,
|
|
1084
|
+
config: finalConfig,
|
|
1049
1085
|
},
|
|
1050
|
-
|
|
1051
|
-
|
|
1086
|
+
message: `Advanced browser created successfully with ID: ${result.dirId}`,
|
|
1087
|
+
};
|
|
1088
|
+
// Create detailed status text
|
|
1089
|
+
const configSummary = [
|
|
1090
|
+
`**Browser ID:** \`${response.browser.dirId}\``,
|
|
1091
|
+
`**Name:** ${finalConfig.windowName || 'Advanced Browser'}`,
|
|
1092
|
+
`**OS:** ${finalConfig.os || 'Windows'} ${finalConfig.osVersion || ''}`,
|
|
1093
|
+
`**Core Version:** ${finalConfig.coreVersion || LATEST_CORE_VERSION}`,
|
|
1094
|
+
finalConfig.userAgent ? `**User Agent:** ${finalConfig.userAgent.substring(0, 50)}...` : '',
|
|
1095
|
+
`**Search Engine:** ${finalConfig.searchEngine || 'Google'}`,
|
|
1096
|
+
finalConfig.proxyInfo?.proxyCategory !== 'noproxy' ? `**Proxy:** ✅ ${finalConfig.proxyInfo?.proxyCategory} ${finalConfig.proxyInfo?.host}:${finalConfig.proxyInfo?.port}` : '**Proxy:** ❌ No proxy',
|
|
1097
|
+
finalConfig.fingerInfo?.randomFingerprint ? '**Fingerprint:** 🎲 Random' : '**Fingerprint:** 🔒 Fixed',
|
|
1098
|
+
finalConfig.defaultOpenUrl?.length ? `**Default URLs:** ${finalConfig.defaultOpenUrl.length} URL(s)` : '',
|
|
1099
|
+
].filter(Boolean).join('\n');
|
|
1100
|
+
return {
|
|
1101
|
+
content: [
|
|
1102
|
+
{
|
|
1103
|
+
type: 'text',
|
|
1104
|
+
text: `✅ **Advanced Browser Created**\n\n${configSummary}\n\n` +
|
|
1105
|
+
`*Advanced browser configured with complete control. Use \`roxy_open_browsers\` to start it.*`,
|
|
1106
|
+
},
|
|
1107
|
+
],
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
catch (error) {
|
|
1111
|
+
// Check for quota error specifically
|
|
1112
|
+
if (error instanceof RoxyApiError && error.code === 409 &&
|
|
1113
|
+
error.message.includes('额度不足')) {
|
|
1114
|
+
return {
|
|
1115
|
+
content: [{
|
|
1116
|
+
type: 'text',
|
|
1117
|
+
text: `❌ **浏览器创建失败 - 窗口额度不足 / Browser Creation Failed - Insufficient Profiles Quota**\n\n` +
|
|
1118
|
+
`**错误信息 / Error:** ${error.message}\n\n` +
|
|
1119
|
+
`**解决步骤 / Solution Steps:**\n` +
|
|
1120
|
+
`1. 打开 RoxyBrowser 应用 / Open RoxyBrowser app\n` +
|
|
1121
|
+
`2. 前往费用中心 / Go to Billing Center\n` +
|
|
1122
|
+
`3. 购买或升级窗口套餐 / Purchase or upgrade profiles plan\n` +
|
|
1123
|
+
`4. 或者删除不需要的浏览器窗口以释放额度 / Or delete unused browser profiles to free up quota\n` +
|
|
1124
|
+
`5. 等待生效后重试创建 / Retry creation after quota is available\n\n` +
|
|
1125
|
+
`💡 **重要提示 / Important:** 必须使用 \`roxy_delete_browsers\` 删除浏览器才能释放额度,仅关闭浏览器无法释放额度。\n` +
|
|
1126
|
+
`You must use \`roxy_delete_browsers\` to delete profiles to free up quota. Simply closing browsers will NOT free up quota.`,
|
|
1127
|
+
}],
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
// Use enhanced error analysis for other errors
|
|
1131
|
+
const formattedError = ErrorAnalyzer.formatErrorForDisplay(error instanceof Error ? error : new Error('Unknown error'));
|
|
1132
|
+
return {
|
|
1133
|
+
content: [{ type: 'text', text: formattedError }],
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1052
1136
|
}
|
|
1053
1137
|
async handleValidateProxyConfig(args) {
|
|
1054
1138
|
const { proxyInfo } = args;
|
|
@@ -1128,20 +1212,62 @@ class RoxyBrowserMCPServer {
|
|
|
1128
1212
|
if (!params.workspaceId || !params.dirIds || params.dirIds.length === 0) {
|
|
1129
1213
|
throw new Error('workspaceId and dirIds are required');
|
|
1130
1214
|
}
|
|
1131
|
-
const
|
|
1215
|
+
const { successes, failures } = await this.roxyClient.openBrowsers(params.workspaceId, params.dirIds, params.args);
|
|
1216
|
+
// Build success message
|
|
1217
|
+
let message = '';
|
|
1218
|
+
if (successes.length > 0) {
|
|
1219
|
+
message += `✅ **Successfully opened ${successes.length} browser(s):**\n\n` +
|
|
1220
|
+
successes.map(result => `**Browser ${result.dirId || 'Unknown'}** (PID: ${result.pid})\n` +
|
|
1221
|
+
` - CDP WebSocket: \`${result.ws}\`\n` +
|
|
1222
|
+
` - HTTP Endpoint: \`${result.http}\`\n` +
|
|
1223
|
+
` - Core Version: ${result.coreVersion}`).join('\n\n') +
|
|
1224
|
+
'\n\n**Use these WebSocket URLs with playwright-mcp:**\n' +
|
|
1225
|
+
'```bash\n' +
|
|
1226
|
+
successes.map(result => `npx @playwright/mcp@latest --cdp-endpoint "${result.ws}"`).join('\n') +
|
|
1227
|
+
'\n```';
|
|
1228
|
+
}
|
|
1229
|
+
// Build failure message with special handling for quota errors
|
|
1230
|
+
if (failures.length > 0) {
|
|
1231
|
+
if (successes.length > 0) {
|
|
1232
|
+
message += '\n\n---\n\n';
|
|
1233
|
+
}
|
|
1234
|
+
// Check if any failures are quota errors (code 101 or 409)
|
|
1235
|
+
const quotaErrors = failures.filter(f => f.errorCode === 101 || (f.errorCode === 409 && f.error.includes('额度不足')));
|
|
1236
|
+
const otherErrors = failures.filter(f => !quotaErrors.includes(f));
|
|
1237
|
+
if (quotaErrors.length > 0) {
|
|
1238
|
+
message += `❌ **Failed to open ${quotaErrors.length} browser(s) - Insufficient Profiles Quota / 窗口额度不足:**\n\n`;
|
|
1239
|
+
quotaErrors.forEach(failure => {
|
|
1240
|
+
message += ` - Browser ID: \`${failure.dirId}\`\n Error: ${failure.error}\n`;
|
|
1241
|
+
});
|
|
1242
|
+
message += '\n**解决步骤 / Solution Steps:**\n';
|
|
1243
|
+
message += '1. 打开 RoxyBrowser 应用 / Open RoxyBrowser app\n';
|
|
1244
|
+
message += '2. 前往费用中心 / Go to Billing Center\n';
|
|
1245
|
+
message += '3. 购买或升级窗口套餐 / Purchase or upgrade profiles plan\n';
|
|
1246
|
+
message += '4. 或者删除不需要的浏览器窗口以释放额度 / Or delete unused browser profiles to free up quota\n\n';
|
|
1247
|
+
message += '💡 **重要提示 / Important:** 必须使用 `roxy_delete_browsers` 删除浏览器才能释放额度,仅关闭浏览器无法释放额度。\n';
|
|
1248
|
+
message += 'You must use `roxy_delete_browsers` to delete profiles to free up quota. Simply closing browsers will NOT free up quota.';
|
|
1249
|
+
}
|
|
1250
|
+
if (otherErrors.length > 0) {
|
|
1251
|
+
if (quotaErrors.length > 0) {
|
|
1252
|
+
message += '\n\n';
|
|
1253
|
+
}
|
|
1254
|
+
message += `❌ **Failed to open ${otherErrors.length} browser(s) - Other Errors:**\n\n`;
|
|
1255
|
+
otherErrors.forEach(failure => {
|
|
1256
|
+
message += ` - Browser ID: \`${failure.dirId}\`\n`;
|
|
1257
|
+
message += ` Error: ${failure.error}\n`;
|
|
1258
|
+
message += ` Retryable: ${failure.retryable ? '✅ Yes' : '❌ No'}\n`;
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
// If all failed
|
|
1263
|
+
if (successes.length === 0 && failures.length > 0) {
|
|
1264
|
+
message = `❌ **Failed to open all ${failures.length} browser(s)**\n\n` + message;
|
|
1265
|
+
}
|
|
1132
1266
|
return {
|
|
1133
1267
|
content: [
|
|
1134
1268
|
{
|
|
1135
1269
|
type: 'text',
|
|
1136
|
-
text:
|
|
1137
|
-
results.map(result => `**Browser ${result.dirId || 'Unknown'}** (PID: ${result.pid})\n` +
|
|
1138
|
-
` - CDP WebSocket: \`${result.ws}\`\n` +
|
|
1139
|
-
` - HTTP Endpoint: \`${result.http}\`\n` +
|
|
1140
|
-
` - Core Version: ${result.coreVersion}`).join('\n\n') +
|
|
1141
|
-
'\n\n**Use these WebSocket URLs with playwright-mcp:**\n' +
|
|
1142
|
-
'```bash\n' +
|
|
1143
|
-
results.map(result => `npx @playwright/mcp@latest --cdp-endpoint "${result.ws}"`).join('\n') +
|
|
1144
|
-
'\n```',
|
|
1270
|
+
text: message,
|
|
1145
1271
|
},
|
|
1146
1272
|
],
|
|
1147
1273
|
};
|
|
@@ -1405,20 +1531,30 @@ class RoxyBrowserMCPServer {
|
|
|
1405
1531
|
throw new Error('workspaceId and dirId are required');
|
|
1406
1532
|
}
|
|
1407
1533
|
const detail = await this.roxyClient.getBrowserDetail(workspaceId, dirId);
|
|
1534
|
+
// Save cookie count before removing cookies to save tokens
|
|
1535
|
+
const cookieCount = detail.cookie?.length || 0;
|
|
1536
|
+
// Create a copy without cookies (cookies can be very large)
|
|
1537
|
+
const { cookie, ...detailWithoutCookies } = detail;
|
|
1538
|
+
// Create summary
|
|
1539
|
+
const summary = `**Browser Details Summary**\n\n` +
|
|
1540
|
+
`**ID:** \`${detail.dirId}\`\n` +
|
|
1541
|
+
`**Name:** ${detail.windowName}\n` +
|
|
1542
|
+
`**Sort Number:** ${detail.windowSortNum}\n` +
|
|
1543
|
+
`**Project:** ${detail.projectName} (ID: ${detail.projectId})\n` +
|
|
1544
|
+
`**OS:** ${detail.os} ${detail.osVersion}\n` +
|
|
1545
|
+
`**Core Version:** ${detail.coreVersion}\n` +
|
|
1546
|
+
`**Search Engine:** ${detail.searchEngine}\n` +
|
|
1547
|
+
`**Open Status:** ${detail.openStatus ? '✅ Opened' : '❌ Closed'}\n` +
|
|
1548
|
+
`**Cookies:** ${cookieCount} stored (excluded from response to save tokens)\n\n` +
|
|
1549
|
+
`**Full Details (JSON):**\n` +
|
|
1550
|
+
'```json\n' +
|
|
1551
|
+
JSON.stringify(detailWithoutCookies, null, 2) +
|
|
1552
|
+
'\n```';
|
|
1408
1553
|
return {
|
|
1409
1554
|
content: [
|
|
1410
1555
|
{
|
|
1411
1556
|
type: 'text',
|
|
1412
|
-
text:
|
|
1413
|
-
`**ID:** \`${detail.dirId}\`\n` +
|
|
1414
|
-
`**Name:** ${detail.windowName}\n` +
|
|
1415
|
-
`**OS:** ${detail.os} ${detail.osVersion}\n` +
|
|
1416
|
-
`**Core:** ${detail.coreVersion}\n` +
|
|
1417
|
-
`**User Agent:** ${detail.userAgent}\n` +
|
|
1418
|
-
`**Proxy:** ${detail.proxyInfo?.host || 'None'}:${detail.proxyInfo?.port || ''}\n` +
|
|
1419
|
-
`**Created:** ${detail.createTime}\n` +
|
|
1420
|
-
`**Updated:** ${detail.updateTime}\n` +
|
|
1421
|
-
`**Open Status:** ${detail.openStatus ? 'Opened' : 'Closed'}`,
|
|
1557
|
+
text: summary,
|
|
1422
1558
|
},
|
|
1423
1559
|
],
|
|
1424
1560
|
};
|