@roxybrowser/openapi 1.0.13-beta.6 → 1.0.13
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 +32 -2
- package/lib/cli.cjs +59 -152
- package/lib/cli.cjs.map +1 -1
- package/lib/cli.js +55 -152
- package/lib/cli.js.map +1 -1
- package/lib/index.cjs +53 -150
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +14 -527
- package/lib/index.d.ts +14 -527
- package/lib/index.js +53 -150
- package/lib/index.js.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -177,8 +177,8 @@ This allows you to build custom UIs, scripts, or other MCP servers that reuse Ro
|
|
|
177
177
|
- `roxy_list_labels` - Get browser labels/tags for organization
|
|
178
178
|
|
|
179
179
|
### Proxy
|
|
180
|
-
- `roxy_list_proxies` - List proxy configurations in a workspace
|
|
181
|
-
- `roxy_store_proxies` - Get list of proxies you've purchased (store)
|
|
180
|
+
- `roxy_list_proxies` - List proxy configurations in a workspace
|
|
181
|
+
- `roxy_store_proxies` - Get list of proxies you've purchased (store)
|
|
182
182
|
- `roxy_create_proxy` - Create a proxy configuration
|
|
183
183
|
- `roxy_batch_create_proxies` - Create multiple proxies in batch
|
|
184
184
|
- `roxy_detect_proxy` - Detect/test proxy availability
|
|
@@ -254,8 +254,38 @@ npm run dev
|
|
|
254
254
|
|
|
255
255
|
# Build for production
|
|
256
256
|
npm run build
|
|
257
|
+
|
|
258
|
+
# Build and run the test suite
|
|
259
|
+
npm test
|
|
260
|
+
|
|
261
|
+
# Launch MCP Inspector against the local stdio server
|
|
262
|
+
ROXY_API_KEY=your-key npm run inspect
|
|
257
263
|
```
|
|
258
264
|
|
|
265
|
+
### Test Strategy
|
|
266
|
+
|
|
267
|
+
The repository now includes a lightweight test setup based on Node's built-in test runner, so no extra test framework is required.
|
|
268
|
+
|
|
269
|
+
- `test/utils.test.mjs`: config resolution and HTTP request wrapper behavior
|
|
270
|
+
- `test/tools.test.mjs`: tool handler formatting and health-check output
|
|
271
|
+
- `test/server.test.mjs`: in-memory MCP integration using the official SDK client and transport
|
|
272
|
+
|
|
273
|
+
`npm test` builds `lib/` first, then runs the tests against the built artifacts. This keeps the test path close to what gets published.
|
|
274
|
+
|
|
275
|
+
### MCP Inspector
|
|
276
|
+
|
|
277
|
+
Use the official MCP Inspector to debug tool discovery and tool calls locally:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
# Web UI
|
|
281
|
+
ROXY_API_KEY=your-key npm run inspect
|
|
282
|
+
|
|
283
|
+
# CLI mode
|
|
284
|
+
ROXY_API_KEY=your-key npm run inspect:cli -- --method tools/list
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Set `ROXY_API_HOST` as needed before launching Inspector.
|
|
288
|
+
|
|
259
289
|
## API Reference
|
|
260
290
|
|
|
261
291
|
### Configuration
|
package/lib/cli.cjs
CHANGED
|
@@ -5,6 +5,11 @@ var commander = require('commander');
|
|
|
5
5
|
var index_js = require('@modelcontextprotocol/sdk/server/index.js');
|
|
6
6
|
var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
7
7
|
var types_js = require('@modelcontextprotocol/sdk/types.js');
|
|
8
|
+
var dotenv = require('dotenv');
|
|
9
|
+
|
|
10
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
|
+
|
|
12
|
+
var dotenv__default = /*#__PURE__*/_interopDefault(dotenv);
|
|
8
13
|
|
|
9
14
|
// src/types.ts
|
|
10
15
|
var ConfigError = class extends Error {
|
|
@@ -2123,6 +2128,14 @@ var ListBrowsers = class {
|
|
|
2123
2128
|
searchParams.append("page_index", params.pageIndex.toString());
|
|
2124
2129
|
if (params.pageSize)
|
|
2125
2130
|
searchParams.append("page_size", params.pageSize.toString());
|
|
2131
|
+
if (params.windowSortNum) {
|
|
2132
|
+
if (params.windowSortNum.includes("-")) {
|
|
2133
|
+
const [_, serialNo] = params.windowSortNum.split("-").map((s) => s.trim());
|
|
2134
|
+
searchParams.append("windowSortNum", serialNo);
|
|
2135
|
+
} else {
|
|
2136
|
+
searchParams.append("windowSortNum", params.windowSortNum);
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2126
2139
|
const result = await request(`/browser/list_v3?${searchParams}`, {
|
|
2127
2140
|
method: "GET"
|
|
2128
2141
|
});
|
|
@@ -2137,23 +2150,29 @@ var ListBrowsers = class {
|
|
|
2137
2150
|
const pageSize = params.pageSize ?? 15;
|
|
2138
2151
|
const totalPages = Math.max(1, Math.ceil((data.total || 0) / pageSize));
|
|
2139
2152
|
const hasNextPage = currentPage < totalPages;
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
${data.
|
|
2143
|
-
const
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
-
|
|
2148
|
-
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2153
|
+
const readable = [];
|
|
2154
|
+
if (data.total > 0) {
|
|
2155
|
+
readable.push(`Found ${data.total} browsers in workspace ${params.workspaceId}:`);
|
|
2156
|
+
const browserList = data.rows.map((browser) => {
|
|
2157
|
+
const serialNo = `${browser.workspaceName?.slice(0, 3).toLocaleUpperCase()}-${browser.windowSortNum}`;
|
|
2158
|
+
const info = [
|
|
2159
|
+
`Profile Name: **${browser.windowName || "Unnamed"}** (SN: ${serialNo})`,
|
|
2160
|
+
` - CoreVersion: ${browser.coreVersion}`,
|
|
2161
|
+
` - OS: ${browser.os} ${browser.osVersion}`
|
|
2162
|
+
];
|
|
2163
|
+
if (browser.windowRemark) {
|
|
2164
|
+
info.push(` - Remark: ${browser.windowRemark}`);
|
|
2165
|
+
}
|
|
2166
|
+
return info.join("\n");
|
|
2167
|
+
}).join("\n\n");
|
|
2168
|
+
readable.push(browserList);
|
|
2169
|
+
if (totalPages > 1) {
|
|
2170
|
+
readable.push(`Pagination: page=${currentPage}, totalPages=${totalPages}, hasNext=${hasNextPage}`);
|
|
2171
|
+
}
|
|
2172
|
+
} else {
|
|
2173
|
+
readable.push(`No browsers found in workspace ${params.workspaceId}.`);
|
|
2174
|
+
}
|
|
2175
|
+
text = readable.join("\n\n");
|
|
2157
2176
|
}
|
|
2158
2177
|
return {
|
|
2159
2178
|
content: [
|
|
@@ -2317,6 +2336,10 @@ var GetBrowserDetail = class {
|
|
|
2317
2336
|
dirId: {
|
|
2318
2337
|
type: "string",
|
|
2319
2338
|
description: "Browser directory ID"
|
|
2339
|
+
},
|
|
2340
|
+
windowSortNum: {
|
|
2341
|
+
type: "string",
|
|
2342
|
+
description: "Filter by window `Serial No` (e.g. 1, 102)"
|
|
2320
2343
|
}
|
|
2321
2344
|
},
|
|
2322
2345
|
required: ["workspaceId", "dirId"]
|
|
@@ -2342,6 +2365,14 @@ var GetBrowserDetail = class {
|
|
|
2342
2365
|
const searchParams = new URLSearchParams();
|
|
2343
2366
|
searchParams.append("workspaceId", params.workspaceId.toString());
|
|
2344
2367
|
searchParams.append("dirId", params.dirId);
|
|
2368
|
+
if (params.windowSortNum) {
|
|
2369
|
+
if (params.windowSortNum.includes("-")) {
|
|
2370
|
+
const [_, serialNo] = params.windowSortNum.split("-").map((s) => s.trim());
|
|
2371
|
+
searchParams.append("windowSortNum", serialNo);
|
|
2372
|
+
} else {
|
|
2373
|
+
searchParams.append("windowSortNum", params.windowSortNum);
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2345
2376
|
const result = await request(`/browser/detail?${searchParams}`, {
|
|
2346
2377
|
method: "GET"
|
|
2347
2378
|
});
|
|
@@ -2774,26 +2805,10 @@ ${ws.project_details.map(
|
|
|
2774
2805
|
};
|
|
2775
2806
|
var HealthCheck = class {
|
|
2776
2807
|
name = "roxy_health_check";
|
|
2777
|
-
description = "Check
|
|
2808
|
+
description = "Check whether the RoxyBrowser server is running and reachable.";
|
|
2778
2809
|
inputSchema = {
|
|
2779
2810
|
type: "object",
|
|
2780
|
-
properties: {
|
|
2781
|
-
includeWorkspaceCheck: {
|
|
2782
|
-
type: "boolean",
|
|
2783
|
-
description: "Include workspace connectivity tests (optional, default: true)",
|
|
2784
|
-
default: true
|
|
2785
|
-
},
|
|
2786
|
-
includeBrowserCheck: {
|
|
2787
|
-
type: "boolean",
|
|
2788
|
-
description: "Include browser availability checks (optional, default: true)",
|
|
2789
|
-
default: true
|
|
2790
|
-
},
|
|
2791
|
-
verbose: {
|
|
2792
|
-
type: "boolean",
|
|
2793
|
-
description: "Include detailed diagnostic information (optional, default: false)",
|
|
2794
|
-
default: false
|
|
2795
|
-
}
|
|
2796
|
-
}
|
|
2811
|
+
properties: {}
|
|
2797
2812
|
};
|
|
2798
2813
|
get schema() {
|
|
2799
2814
|
return {
|
|
@@ -2802,126 +2817,19 @@ var HealthCheck = class {
|
|
|
2802
2817
|
inputSchema: this.inputSchema
|
|
2803
2818
|
};
|
|
2804
2819
|
}
|
|
2805
|
-
async handle(
|
|
2806
|
-
|
|
2807
|
-
let healthStatus = "unknown";
|
|
2808
|
-
let healthError = "";
|
|
2820
|
+
async handle(_params) {
|
|
2821
|
+
let text = "";
|
|
2809
2822
|
try {
|
|
2810
|
-
const
|
|
2823
|
+
const result = await request("/health", {
|
|
2811
2824
|
method: "GET"
|
|
2812
2825
|
});
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
healthStatus = "unhealthy";
|
|
2817
|
-
healthError = healthResult.msg || "Health check failed";
|
|
2818
|
-
}
|
|
2826
|
+
text = result.code === 0 ? "\u2705 **Server is healthy**\n\nThe RoxyBrowser server is running and reachable." : `\u274C **Server health check failed**
|
|
2827
|
+
|
|
2828
|
+
${result.msg || "Unknown server response"}`;
|
|
2819
2829
|
} catch (error) {
|
|
2820
|
-
|
|
2821
|
-
healthError = error.message || "Failed to connect to server";
|
|
2822
|
-
}
|
|
2823
|
-
let text = `## \u{1F50D} \u5065\u5EB7\u68C0\u67E5\u62A5\u544A / Health Check Report
|
|
2830
|
+
text = `\u274C **Server is unavailable**
|
|
2824
2831
|
|
|
2825
|
-
`;
|
|
2826
|
-
text += `### \u{1F310} \u670D\u52A1\u5668\u72B6\u6001 / Server Status
|
|
2827
|
-
`;
|
|
2828
|
-
text += `- **\u670D\u52A1\u5668\u8FDE\u63A5 / Server Connection**: ${healthStatus === "healthy" ? "\u2705 \u6B63\u5E38" : "\u274C \u5F02\u5E38"}
|
|
2829
|
-
`;
|
|
2830
|
-
if (healthStatus !== "healthy" && healthError) {
|
|
2831
|
-
text += `- **\u9519\u8BEF\u4FE1\u606F / Error**: ${healthError}
|
|
2832
|
-
`;
|
|
2833
|
-
}
|
|
2834
|
-
if (includeWorkspaceCheck && healthStatus === "healthy") {
|
|
2835
|
-
try {
|
|
2836
|
-
const workspaceResult = await request("/browser/workspace?page_index=1&page_size=5", {
|
|
2837
|
-
method: "GET"
|
|
2838
|
-
});
|
|
2839
|
-
if (workspaceResult.code === 0) {
|
|
2840
|
-
const workspaces = workspaceResult.data;
|
|
2841
|
-
text += `
|
|
2842
|
-
### \u{1F4C1} \u5DE5\u4F5C\u533A\u4FE1\u606F / Workspace Information
|
|
2843
|
-
`;
|
|
2844
|
-
text += `- **\u53EF\u7528\u5DE5\u4F5C\u533A / Available Workspaces**: ${workspaces.total}
|
|
2845
|
-
`;
|
|
2846
|
-
if (workspaces.rows && workspaces.rows.length > 0) {
|
|
2847
|
-
text += `- **\u5DE5\u4F5C\u533A\u8BE6\u60C5 / Workspace Details**:
|
|
2848
|
-
`;
|
|
2849
|
-
workspaces.rows.slice(0, 3).forEach((ws) => {
|
|
2850
|
-
const projectCount = ws.project_details?.length || 0;
|
|
2851
|
-
text += ` - ${ws.workspaceName} (ID: ${ws.id}) - ${projectCount} projects
|
|
2852
|
-
`;
|
|
2853
|
-
});
|
|
2854
|
-
if (workspaces.total > 3) {
|
|
2855
|
-
text += ` - ... and ${workspaces.total - 3} more
|
|
2856
|
-
`;
|
|
2857
|
-
}
|
|
2858
|
-
}
|
|
2859
|
-
} else {
|
|
2860
|
-
text += `
|
|
2861
|
-
### \u{1F4C1} \u5DE5\u4F5C\u533A\u4FE1\u606F / Workspace Information
|
|
2862
|
-
`;
|
|
2863
|
-
text += `- **\u72B6\u6001**: \u26A0\uFE0F \u65E0\u6CD5\u83B7\u53D6\u5DE5\u4F5C\u533A\u4FE1\u606F
|
|
2864
|
-
`;
|
|
2865
|
-
text += `- **\u9519\u8BEF**: ${workspaceResult.msg}
|
|
2866
|
-
`;
|
|
2867
|
-
}
|
|
2868
|
-
} catch (error) {
|
|
2869
|
-
text += `
|
|
2870
|
-
### \u{1F4C1} \u5DE5\u4F5C\u533A\u4FE1\u606F / Workspace Information
|
|
2871
|
-
`;
|
|
2872
|
-
text += `- **\u72B6\u6001**: \u274C \u65E0\u6CD5\u83B7\u53D6\u5DE5\u4F5C\u533A\u4FE1\u606F
|
|
2873
|
-
`;
|
|
2874
|
-
text += `- **\u9519\u8BEF**: ${error.message || "Unknown error"}
|
|
2875
|
-
`;
|
|
2876
|
-
}
|
|
2877
|
-
}
|
|
2878
|
-
if (includeBrowserCheck && healthStatus === "healthy") {
|
|
2879
|
-
try {
|
|
2880
|
-
const workspaceResult = await request("/browser/workspace?page_index=1&page_size=1", {
|
|
2881
|
-
method: "GET"
|
|
2882
|
-
});
|
|
2883
|
-
if (workspaceResult.code === 0 && workspaceResult.data.rows && workspaceResult.data.rows.length > 0) {
|
|
2884
|
-
const firstWorkspace = workspaceResult.data.rows[0];
|
|
2885
|
-
const browserResult = await request(`/browser/list_v3?workspaceId=${firstWorkspace.id}&page_index=1&page_size=5`, {
|
|
2886
|
-
method: "GET"
|
|
2887
|
-
});
|
|
2888
|
-
if (browserResult.code === 0) {
|
|
2889
|
-
const browsers = browserResult.data;
|
|
2890
|
-
text += `
|
|
2891
|
-
### \u{1F310} \u6D4F\u89C8\u5668\u4FE1\u606F / Browser Information
|
|
2892
|
-
`;
|
|
2893
|
-
text += `- **\u5DE5\u4F5C\u533A / Workspace**: ${firstWorkspace.workspaceName} (ID: ${firstWorkspace.id})
|
|
2894
|
-
`;
|
|
2895
|
-
text += `- **\u6D4F\u89C8\u5668\u603B\u6570 / Total Browsers**: ${browsers.total}
|
|
2896
|
-
`;
|
|
2897
|
-
if (browsers.rows && browsers.rows.length > 0) {
|
|
2898
|
-
text += `- **\u6D4F\u89C8\u5668\u793A\u4F8B / Browser Examples**:
|
|
2899
|
-
`;
|
|
2900
|
-
browsers.rows.slice(0, 3).forEach((browser) => {
|
|
2901
|
-
text += ` - ${browser.windowName || "Unnamed"} (ID: ${browser.dirId}) - ${browser.status}
|
|
2902
|
-
`;
|
|
2903
|
-
});
|
|
2904
|
-
}
|
|
2905
|
-
}
|
|
2906
|
-
}
|
|
2907
|
-
} catch (error) {
|
|
2908
|
-
text += `
|
|
2909
|
-
### \u{1F310} \u6D4F\u89C8\u5668\u4FE1\u606F / Browser Information
|
|
2910
|
-
`;
|
|
2911
|
-
text += `- **\u72B6\u6001**: \u26A0\uFE0F \u65E0\u6CD5\u83B7\u53D6\u6D4F\u89C8\u5668\u4FE1\u606F
|
|
2912
|
-
`;
|
|
2913
|
-
text += `- **\u9519\u8BEF**: ${error.message || "Unknown error"}
|
|
2914
|
-
`;
|
|
2915
|
-
}
|
|
2916
|
-
}
|
|
2917
|
-
if (verbose && healthStatus === "healthy") {
|
|
2918
|
-
text += `
|
|
2919
|
-
### \u{1F4CA} \u8BE6\u7EC6\u4FE1\u606F / Detailed Information
|
|
2920
|
-
`;
|
|
2921
|
-
text += `- **\u5065\u5EB7\u68C0\u67E5\u65F6\u95F4 / Check Time**: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
2922
|
-
`;
|
|
2923
|
-
text += `- **\u68C0\u67E5\u6A21\u5F0F / Check Mode**: ${includeWorkspaceCheck ? "Workspace + " : ""}${includeBrowserCheck ? "Browser" : ""}
|
|
2924
|
-
`;
|
|
2832
|
+
${error?.message || "Failed to connect to the server"}`;
|
|
2925
2833
|
}
|
|
2926
2834
|
return {
|
|
2927
2835
|
content: [
|
|
@@ -3081,8 +2989,7 @@ async function runServer() {
|
|
|
3081
2989
|
const server = new RoxyBrowserMCPServer();
|
|
3082
2990
|
await server.run();
|
|
3083
2991
|
}
|
|
3084
|
-
|
|
3085
|
-
// src/cli.ts
|
|
2992
|
+
dotenv__default.default.config();
|
|
3086
2993
|
var PKG_VERSION = "1.0.9";
|
|
3087
2994
|
var program = new commander.Command();
|
|
3088
2995
|
program.name("roxy-browser-mcp").description("RoxyBrowser MCP Server - Model Context Protocol server for RoxyBrowser automation").version(PKG_VERSION, "-V, --version", "Show version").option(
|