@aluvia/sdk 1.3.0 → 1.4.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 +2 -1
- package/dist/cjs/bin/cli-adapter.js +16 -0
- package/dist/cjs/bin/open.js +55 -31
- package/dist/esm/bin/cli-adapter.js +8 -0
- package/dist/esm/bin/cli.js +0 -0
- package/dist/esm/bin/open.js +56 -32
- package/dist/types/bin/cli-adapter.d.ts +8 -0
- package/package.json +14 -6
- package/dist/cjs/bin/mcp-server.js +0 -220
- package/dist/cjs/bin/mcp-tools.js +0 -90
- package/dist/cjs/client/PageLoadDetection.js +0 -175
- package/dist/esm/bin/mcp-server.js +0 -185
- package/dist/esm/bin/mcp-tools.js +0 -78
- package/dist/esm/client/PageLoadDetection.js +0 -171
- package/dist/types/bin/mcp-server.d.ts +0 -2
- package/dist/types/bin/mcp-tools.d.ts +0 -46
- package/dist/types/client/PageLoadDetection.d.ts +0 -93
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@ This SDK gives you everything you need:
|
|
|
16
16
|
- **Adapters for every tool** — Playwright, Puppeteer, Selenium, Axios, got, and Node's fetch
|
|
17
17
|
- **IP rotation and geo targeting** — rotate IPs or target specific US regions at runtime
|
|
18
18
|
- **REST API wrapper** — manage connections, check usage, and build custom tooling with `AluviaApi`
|
|
19
|
+
- **MCP server** — for Model Context Protocol (MCP) only, use the separate package: `npm install @aluvia/mcp` and run `npx aluvia-mcp`. See [mcp/README.md](mcp/README.md) and [MCP Server Guide](docs/mcp-server-guide.md).
|
|
19
20
|
|
|
20
21
|
---
|
|
21
22
|
|
|
@@ -58,7 +59,7 @@ aluvia session start https://example.com --auto-unblock --run your-script.js
|
|
|
58
59
|
|
|
59
60
|
## Skills
|
|
60
61
|
|
|
61
|
-
- Claude code
|
|
62
|
+
- Claude code skill
|
|
62
63
|
- OpenClaw skill
|
|
63
64
|
|
|
64
65
|
---
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Re-exports for @aluvia/mcp. MCP package imports from @aluvia/sdk/cli.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.captureOutput = exports.handleOpen = exports.handleGeos = exports.handleAccount = exports.handleSession = void 0;
|
|
7
|
+
var session_js_1 = require("./session.js");
|
|
8
|
+
Object.defineProperty(exports, "handleSession", { enumerable: true, get: function () { return session_js_1.handleSession; } });
|
|
9
|
+
var account_js_1 = require("./account.js");
|
|
10
|
+
Object.defineProperty(exports, "handleAccount", { enumerable: true, get: function () { return account_js_1.handleAccount; } });
|
|
11
|
+
var geos_js_1 = require("./geos.js");
|
|
12
|
+
Object.defineProperty(exports, "handleGeos", { enumerable: true, get: function () { return geos_js_1.handleGeos; } });
|
|
13
|
+
var open_js_1 = require("./open.js");
|
|
14
|
+
Object.defineProperty(exports, "handleOpen", { enumerable: true, get: function () { return open_js_1.handleOpen; } });
|
|
15
|
+
var mcp_helpers_js_1 = require("./mcp-helpers.js");
|
|
16
|
+
Object.defineProperty(exports, "captureOutput", { enumerable: true, get: function () { return mcp_helpers_js_1.captureOutput; } });
|
package/dist/cjs/bin/open.js
CHANGED
|
@@ -42,6 +42,21 @@ const node_child_process_1 = require("node:child_process");
|
|
|
42
42
|
const fs = __importStar(require("node:fs"));
|
|
43
43
|
const path = __importStar(require("node:path"));
|
|
44
44
|
const node_url_1 = require("node:url");
|
|
45
|
+
// Determine the directory of this module at load time
|
|
46
|
+
// @ts-ignore - import.meta.url exists at runtime in ESM
|
|
47
|
+
const thisModuleDir = path.dirname((0, node_url_1.fileURLToPath)(import.meta.url));
|
|
48
|
+
/**
|
|
49
|
+
* Get the path to cli.js for spawning daemon processes.
|
|
50
|
+
* Looks in the same directory as this module (works for both dev and installed).
|
|
51
|
+
*/
|
|
52
|
+
function getCliScriptPath() {
|
|
53
|
+
// cli.js should be in the same directory as open.js
|
|
54
|
+
const cliPath = path.join(thisModuleDir, 'cli.js');
|
|
55
|
+
if (fs.existsSync(cliPath)) {
|
|
56
|
+
return cliPath;
|
|
57
|
+
}
|
|
58
|
+
throw new Error(`Could not find cli.js at ${cliPath}`);
|
|
59
|
+
}
|
|
45
60
|
/**
|
|
46
61
|
* Called from cli.ts when running `session start <url>`.
|
|
47
62
|
* Spawns the actual browser in a detached child and polls until ready.
|
|
@@ -96,7 +111,9 @@ function handleOpen({ url, connectionId, headless, sessionName, autoUnblock, dis
|
|
|
96
111
|
}
|
|
97
112
|
let child;
|
|
98
113
|
try {
|
|
99
|
-
|
|
114
|
+
// Get the path to cli.js in the same directory as this module
|
|
115
|
+
const cliPath = getCliScriptPath();
|
|
116
|
+
child = (0, node_child_process_1.spawn)(process.execPath, [cliPath, ...args], {
|
|
100
117
|
detached: true,
|
|
101
118
|
stdio: ['ignore', out, out],
|
|
102
119
|
env: { ...process.env, ALUVIA_API_KEY: apiKey },
|
|
@@ -109,42 +126,49 @@ function handleOpen({ url, connectionId, headless, sessionName, autoUnblock, dis
|
|
|
109
126
|
}
|
|
110
127
|
fs.closeSync(out);
|
|
111
128
|
// Wait for the daemon to be fully ready (lock file with ready: true)
|
|
112
|
-
return new Promise(() => {
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
113
130
|
let attempts = 0;
|
|
114
131
|
const maxAttempts = 240; // 60 seconds max
|
|
115
132
|
const poll = setInterval(() => {
|
|
116
133
|
attempts++;
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
134
|
+
try {
|
|
135
|
+
// Early exit if daemon process died
|
|
136
|
+
if (child.pid && !(0, lock_js_1.isProcessAlive)(child.pid)) {
|
|
137
|
+
clearInterval(poll);
|
|
138
|
+
(0, lock_js_1.removeLock)(session);
|
|
139
|
+
(0, cli_js_1.output)({
|
|
140
|
+
browserSession: session,
|
|
141
|
+
error: 'Browser process exited unexpectedly.',
|
|
142
|
+
logFile,
|
|
143
|
+
}, 1);
|
|
144
|
+
}
|
|
145
|
+
const lock = (0, lock_js_1.readLock)(session);
|
|
146
|
+
if (lock && lock.ready) {
|
|
147
|
+
clearInterval(poll);
|
|
148
|
+
(0, cli_js_1.output)({
|
|
149
|
+
browserSession: session,
|
|
150
|
+
pid: lock.pid,
|
|
151
|
+
startUrl: lock.url ?? null,
|
|
152
|
+
cdpUrl: lock.cdpUrl ?? null,
|
|
153
|
+
connectionId: lock.connectionId ?? null,
|
|
154
|
+
blockDetection: lock.blockDetection ?? false,
|
|
155
|
+
autoUnblock: lock.autoUnblock ?? false,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
if (attempts >= maxAttempts) {
|
|
159
|
+
clearInterval(poll);
|
|
160
|
+
const alive = child.pid ? (0, lock_js_1.isProcessAlive)(child.pid) : false;
|
|
161
|
+
(0, cli_js_1.output)({
|
|
162
|
+
browserSession: session,
|
|
163
|
+
error: alive ? 'Browser is still initializing (timeout).' : 'Browser process exited unexpectedly.',
|
|
164
|
+
logFile,
|
|
165
|
+
}, 1);
|
|
166
|
+
}
|
|
139
167
|
}
|
|
140
|
-
|
|
168
|
+
catch (err) {
|
|
169
|
+
// In MCP capture mode, output() throws MCPOutputCapture which we need to propagate
|
|
141
170
|
clearInterval(poll);
|
|
142
|
-
|
|
143
|
-
(0, cli_js_1.output)({
|
|
144
|
-
browserSession: session,
|
|
145
|
-
error: alive ? 'Browser is still initializing (timeout).' : 'Browser process exited unexpectedly.',
|
|
146
|
-
logFile,
|
|
147
|
-
}, 1);
|
|
171
|
+
reject(err);
|
|
148
172
|
}
|
|
149
173
|
}, 250);
|
|
150
174
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-exports for @aluvia/mcp. MCP package imports from @aluvia/sdk/cli.
|
|
3
|
+
*/
|
|
4
|
+
export { handleSession } from "./session.js";
|
|
5
|
+
export { handleAccount } from "./account.js";
|
|
6
|
+
export { handleGeos } from "./geos.js";
|
|
7
|
+
export { handleOpen } from "./open.js";
|
|
8
|
+
export { captureOutput } from "./mcp-helpers.js";
|
package/dist/esm/bin/cli.js
CHANGED
|
File without changes
|
package/dist/esm/bin/open.js
CHANGED
|
@@ -4,7 +4,22 @@ import { output } from './cli.js';
|
|
|
4
4
|
import { spawn } from 'node:child_process';
|
|
5
5
|
import * as fs from 'node:fs';
|
|
6
6
|
import * as path from 'node:path';
|
|
7
|
-
import { pathToFileURL } from 'node:url';
|
|
7
|
+
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
8
|
+
// Determine the directory of this module at load time
|
|
9
|
+
// @ts-ignore - import.meta.url exists at runtime in ESM
|
|
10
|
+
const thisModuleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
/**
|
|
12
|
+
* Get the path to cli.js for spawning daemon processes.
|
|
13
|
+
* Looks in the same directory as this module (works for both dev and installed).
|
|
14
|
+
*/
|
|
15
|
+
function getCliScriptPath() {
|
|
16
|
+
// cli.js should be in the same directory as open.js
|
|
17
|
+
const cliPath = path.join(thisModuleDir, 'cli.js');
|
|
18
|
+
if (fs.existsSync(cliPath)) {
|
|
19
|
+
return cliPath;
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`Could not find cli.js at ${cliPath}`);
|
|
22
|
+
}
|
|
8
23
|
/**
|
|
9
24
|
* Called from cli.ts when running `session start <url>`.
|
|
10
25
|
* Spawns the actual browser in a detached child and polls until ready.
|
|
@@ -59,7 +74,9 @@ export function handleOpen({ url, connectionId, headless, sessionName, autoUnblo
|
|
|
59
74
|
}
|
|
60
75
|
let child;
|
|
61
76
|
try {
|
|
62
|
-
|
|
77
|
+
// Get the path to cli.js in the same directory as this module
|
|
78
|
+
const cliPath = getCliScriptPath();
|
|
79
|
+
child = spawn(process.execPath, [cliPath, ...args], {
|
|
63
80
|
detached: true,
|
|
64
81
|
stdio: ['ignore', out, out],
|
|
65
82
|
env: { ...process.env, ALUVIA_API_KEY: apiKey },
|
|
@@ -72,42 +89,49 @@ export function handleOpen({ url, connectionId, headless, sessionName, autoUnblo
|
|
|
72
89
|
}
|
|
73
90
|
fs.closeSync(out);
|
|
74
91
|
// Wait for the daemon to be fully ready (lock file with ready: true)
|
|
75
|
-
return new Promise(() => {
|
|
92
|
+
return new Promise((resolve, reject) => {
|
|
76
93
|
let attempts = 0;
|
|
77
94
|
const maxAttempts = 240; // 60 seconds max
|
|
78
95
|
const poll = setInterval(() => {
|
|
79
96
|
attempts++;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
97
|
+
try {
|
|
98
|
+
// Early exit if daemon process died
|
|
99
|
+
if (child.pid && !isProcessAlive(child.pid)) {
|
|
100
|
+
clearInterval(poll);
|
|
101
|
+
removeLock(session);
|
|
102
|
+
output({
|
|
103
|
+
browserSession: session,
|
|
104
|
+
error: 'Browser process exited unexpectedly.',
|
|
105
|
+
logFile,
|
|
106
|
+
}, 1);
|
|
107
|
+
}
|
|
108
|
+
const lock = readLock(session);
|
|
109
|
+
if (lock && lock.ready) {
|
|
110
|
+
clearInterval(poll);
|
|
111
|
+
output({
|
|
112
|
+
browserSession: session,
|
|
113
|
+
pid: lock.pid,
|
|
114
|
+
startUrl: lock.url ?? null,
|
|
115
|
+
cdpUrl: lock.cdpUrl ?? null,
|
|
116
|
+
connectionId: lock.connectionId ?? null,
|
|
117
|
+
blockDetection: lock.blockDetection ?? false,
|
|
118
|
+
autoUnblock: lock.autoUnblock ?? false,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (attempts >= maxAttempts) {
|
|
122
|
+
clearInterval(poll);
|
|
123
|
+
const alive = child.pid ? isProcessAlive(child.pid) : false;
|
|
124
|
+
output({
|
|
125
|
+
browserSession: session,
|
|
126
|
+
error: alive ? 'Browser is still initializing (timeout).' : 'Browser process exited unexpectedly.',
|
|
127
|
+
logFile,
|
|
128
|
+
}, 1);
|
|
129
|
+
}
|
|
102
130
|
}
|
|
103
|
-
|
|
131
|
+
catch (err) {
|
|
132
|
+
// In MCP capture mode, output() throws MCPOutputCapture which we need to propagate
|
|
104
133
|
clearInterval(poll);
|
|
105
|
-
|
|
106
|
-
output({
|
|
107
|
-
browserSession: session,
|
|
108
|
-
error: alive ? 'Browser is still initializing (timeout).' : 'Browser process exited unexpectedly.',
|
|
109
|
-
logFile,
|
|
110
|
-
}, 1);
|
|
134
|
+
reject(err);
|
|
111
135
|
}
|
|
112
136
|
}, 250);
|
|
113
137
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-exports for @aluvia/mcp. MCP package imports from @aluvia/sdk/cli.
|
|
3
|
+
*/
|
|
4
|
+
export { handleSession } from "./session.js";
|
|
5
|
+
export { handleAccount } from "./account.js";
|
|
6
|
+
export { handleGeos } from "./geos.js";
|
|
7
|
+
export { handleOpen } from "./open.js";
|
|
8
|
+
export { captureOutput } from "./mcp-helpers.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aluvia/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "Aluvia SDK for Node.js - local smart proxy for automation workloads and AI agents",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Aluvia",
|
|
@@ -22,13 +22,20 @@
|
|
|
22
22
|
"import": "./dist/esm/index.js",
|
|
23
23
|
"require": "./dist/cjs/index.js"
|
|
24
24
|
},
|
|
25
|
+
"./cli": {
|
|
26
|
+
"types": "./dist/types/bin/cli-adapter.d.ts",
|
|
27
|
+
"import": "./dist/esm/bin/cli-adapter.js",
|
|
28
|
+
"require": "./dist/cjs/bin/cli-adapter.js"
|
|
29
|
+
},
|
|
25
30
|
"./package.json": "./package.json"
|
|
26
31
|
},
|
|
27
32
|
"bin": {
|
|
28
33
|
"aluvia": "./dist/esm/bin/cli.js",
|
|
29
|
-
"aluvia-sdk": "./dist/esm/bin/cli.js"
|
|
30
|
-
"aluvia-mcp": "./dist/esm/bin/mcp-server.js"
|
|
34
|
+
"aluvia-sdk": "./dist/esm/bin/cli.js"
|
|
31
35
|
},
|
|
36
|
+
"workspaces": [
|
|
37
|
+
"mcp"
|
|
38
|
+
],
|
|
32
39
|
"files": [
|
|
33
40
|
"dist/**/*",
|
|
34
41
|
"README.md",
|
|
@@ -36,8 +43,10 @@
|
|
|
36
43
|
],
|
|
37
44
|
"scripts": {
|
|
38
45
|
"build": "tsc -p tsconfig.esm.json && tsc -p tsconfig.cjs.json && node -e \"require('fs').mkdirSync('dist/cjs',{recursive:true});require('fs').writeFileSync('dist/cjs/package.json','{\\\"type\\\":\\\"commonjs\\\"}')\"",
|
|
46
|
+
"build:all": "npm run build && npm run build -w @aluvia/mcp",
|
|
39
47
|
"prepare": "npm run build",
|
|
40
|
-
"test": "node --import tsx --test test/integration.test.ts",
|
|
48
|
+
"test": "node --import tsx --test test/integration.test.ts test/mcp-smoke.test.ts",
|
|
49
|
+
"test:mcp": "node mcp/test-stdio.mjs",
|
|
41
50
|
"lint": "prettier --check src test",
|
|
42
51
|
"lint:fix": "prettier --write src test"
|
|
43
52
|
},
|
|
@@ -64,11 +73,10 @@
|
|
|
64
73
|
"typescript": "^5.9.3"
|
|
65
74
|
},
|
|
66
75
|
"dependencies": {
|
|
67
|
-
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
68
76
|
"http-proxy-agent": "^7.0.2",
|
|
69
77
|
"https-proxy-agent": "^7.0.6",
|
|
70
78
|
"playwright": "^1.58.2",
|
|
71
79
|
"proxy-chain": "^2.6.1",
|
|
72
80
|
"undici": "^6.22.0"
|
|
73
81
|
}
|
|
74
|
-
}
|
|
82
|
+
}
|
|
@@ -1,220 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
-
if (k2 === undefined) k2 = k;
|
|
5
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
-
}
|
|
9
|
-
Object.defineProperty(o, k2, desc);
|
|
10
|
-
}) : (function(o, m, k, k2) {
|
|
11
|
-
if (k2 === undefined) k2 = k;
|
|
12
|
-
o[k2] = m[k];
|
|
13
|
-
}));
|
|
14
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
-
}) : function(o, v) {
|
|
17
|
-
o["default"] = v;
|
|
18
|
-
});
|
|
19
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
-
var ownKeys = function(o) {
|
|
21
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
-
var ar = [];
|
|
23
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
-
return ar;
|
|
25
|
-
};
|
|
26
|
-
return ownKeys(o);
|
|
27
|
-
};
|
|
28
|
-
return function (mod) {
|
|
29
|
-
if (mod && mod.__esModule) return mod;
|
|
30
|
-
var result = {};
|
|
31
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
-
__setModuleDefault(result, mod);
|
|
33
|
-
return result;
|
|
34
|
-
};
|
|
35
|
-
})();
|
|
36
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
-
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
38
|
-
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
39
|
-
const zod_1 = require("zod");
|
|
40
|
-
const tools = __importStar(require("./mcp-tools.js"));
|
|
41
|
-
const server = new mcp_js_1.McpServer({
|
|
42
|
-
name: "aluvia",
|
|
43
|
-
version: "1.2.0",
|
|
44
|
-
});
|
|
45
|
-
// --- Session tools ---
|
|
46
|
-
server.tool("session_start", "Start a browser session with Aluvia smart proxy. Spawns a headless browser connected through Aluvia gateway. Returns session details including CDP URL for remote debugging.", {
|
|
47
|
-
url: zod_1.z.string().describe("URL to open in the browser"),
|
|
48
|
-
connectionId: zod_1.z
|
|
49
|
-
.number()
|
|
50
|
-
.int()
|
|
51
|
-
.positive()
|
|
52
|
-
.optional()
|
|
53
|
-
.describe("Use a specific Aluvia connection ID"),
|
|
54
|
-
headful: zod_1.z
|
|
55
|
-
.boolean()
|
|
56
|
-
.optional()
|
|
57
|
-
.describe("Run browser in headful mode (default: headless)"),
|
|
58
|
-
browserSession: zod_1.z
|
|
59
|
-
.string()
|
|
60
|
-
.optional()
|
|
61
|
-
.describe("Custom session name (auto-generated if omitted)"),
|
|
62
|
-
autoUnblock: zod_1.z
|
|
63
|
-
.boolean()
|
|
64
|
-
.optional()
|
|
65
|
-
.describe("Auto-detect blocks and reload through Aluvia proxy"),
|
|
66
|
-
disableBlockDetection: zod_1.z
|
|
67
|
-
.boolean()
|
|
68
|
-
.optional()
|
|
69
|
-
.describe("Disable block detection entirely"),
|
|
70
|
-
}, async (args) => {
|
|
71
|
-
const result = await tools.sessionStart(args);
|
|
72
|
-
return {
|
|
73
|
-
content: [
|
|
74
|
-
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
75
|
-
],
|
|
76
|
-
isError: result.isError,
|
|
77
|
-
};
|
|
78
|
-
});
|
|
79
|
-
server.tool("session_close", "Close one or all running browser sessions. Sends SIGTERM for graceful shutdown, then SIGKILL if needed.", {
|
|
80
|
-
browserSession: zod_1.z
|
|
81
|
-
.string()
|
|
82
|
-
.optional()
|
|
83
|
-
.describe("Name of session to close (auto-selects if only one)"),
|
|
84
|
-
all: zod_1.z.boolean().optional().describe("Close all sessions"),
|
|
85
|
-
}, async (args) => {
|
|
86
|
-
const result = await tools.sessionClose(args);
|
|
87
|
-
return {
|
|
88
|
-
content: [
|
|
89
|
-
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
90
|
-
],
|
|
91
|
-
isError: result.isError,
|
|
92
|
-
};
|
|
93
|
-
});
|
|
94
|
-
server.tool("session_list", "List all active browser sessions with their PIDs, URLs, and proxy configuration.", async () => {
|
|
95
|
-
const result = await tools.sessionList();
|
|
96
|
-
return {
|
|
97
|
-
content: [
|
|
98
|
-
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
99
|
-
],
|
|
100
|
-
isError: result.isError,
|
|
101
|
-
};
|
|
102
|
-
});
|
|
103
|
-
server.tool("session_get", "Get detailed information about a running session including proxy URLs, connection data, and block detection state.", {
|
|
104
|
-
browserSession: zod_1.z
|
|
105
|
-
.string()
|
|
106
|
-
.optional()
|
|
107
|
-
.describe("Name of session (auto-selects if only one)"),
|
|
108
|
-
}, async (args) => {
|
|
109
|
-
const result = await tools.sessionGet(args);
|
|
110
|
-
return {
|
|
111
|
-
content: [
|
|
112
|
-
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
113
|
-
],
|
|
114
|
-
isError: result.isError,
|
|
115
|
-
};
|
|
116
|
-
});
|
|
117
|
-
server.tool("session_rotate_ip", "Rotate the IP address for a running session by generating a new session ID on the Aluvia connection.", {
|
|
118
|
-
browserSession: zod_1.z
|
|
119
|
-
.string()
|
|
120
|
-
.optional()
|
|
121
|
-
.describe("Name of session (auto-selects if only one)"),
|
|
122
|
-
}, async (args) => {
|
|
123
|
-
const result = await tools.sessionRotateIp(args);
|
|
124
|
-
return {
|
|
125
|
-
content: [
|
|
126
|
-
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
127
|
-
],
|
|
128
|
-
isError: result.isError,
|
|
129
|
-
};
|
|
130
|
-
});
|
|
131
|
-
server.tool("session_set_geo", "Set or clear the target geographic region for a running session. Affects which mobile IP pool is used.", {
|
|
132
|
-
geo: zod_1.z.string().optional().describe('Geo code to set (e.g. "US", "GB")'),
|
|
133
|
-
clear: zod_1.z
|
|
134
|
-
.boolean()
|
|
135
|
-
.optional()
|
|
136
|
-
.describe("Clear the target geo instead of setting one"),
|
|
137
|
-
browserSession: zod_1.z
|
|
138
|
-
.string()
|
|
139
|
-
.optional()
|
|
140
|
-
.describe("Name of session (auto-selects if only one)"),
|
|
141
|
-
}, async (args) => {
|
|
142
|
-
const result = await tools.sessionSetGeo(args);
|
|
143
|
-
return {
|
|
144
|
-
content: [
|
|
145
|
-
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
146
|
-
],
|
|
147
|
-
isError: result.isError,
|
|
148
|
-
};
|
|
149
|
-
});
|
|
150
|
-
server.tool("session_set_rules", 'Append or remove proxy routing rules for a running session. Rules are hostname patterns (e.g. "example.com", "*.google.com").', {
|
|
151
|
-
rules: zod_1.z
|
|
152
|
-
.string()
|
|
153
|
-
.optional()
|
|
154
|
-
.describe('Comma-separated rules to append (e.g. "a.com,b.com")'),
|
|
155
|
-
remove: zod_1.z
|
|
156
|
-
.string()
|
|
157
|
-
.optional()
|
|
158
|
-
.describe("Comma-separated rules to remove instead of appending"),
|
|
159
|
-
browserSession: zod_1.z
|
|
160
|
-
.string()
|
|
161
|
-
.optional()
|
|
162
|
-
.describe("Name of session (auto-selects if only one)"),
|
|
163
|
-
}, async (args) => {
|
|
164
|
-
const result = await tools.sessionSetRules(args);
|
|
165
|
-
return {
|
|
166
|
-
content: [
|
|
167
|
-
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
168
|
-
],
|
|
169
|
-
isError: result.isError,
|
|
170
|
-
};
|
|
171
|
-
});
|
|
172
|
-
// --- Account tools ---
|
|
173
|
-
server.tool("account_get", "Get Aluvia account information including plan details and current balance.", async () => {
|
|
174
|
-
const result = await tools.accountGet();
|
|
175
|
-
return {
|
|
176
|
-
content: [
|
|
177
|
-
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
178
|
-
],
|
|
179
|
-
isError: result.isError,
|
|
180
|
-
};
|
|
181
|
-
});
|
|
182
|
-
server.tool("account_usage", "Get Aluvia account usage statistics for a date range.", {
|
|
183
|
-
start: zod_1.z
|
|
184
|
-
.string()
|
|
185
|
-
.optional()
|
|
186
|
-
.describe('Start date filter (ISO8601 format, e.g. "2024-01-01T00:00:00Z")'),
|
|
187
|
-
end: zod_1.z.string().optional().describe("End date filter (ISO8601 format)"),
|
|
188
|
-
}, async (args) => {
|
|
189
|
-
const result = await tools.accountUsage(args);
|
|
190
|
-
return {
|
|
191
|
-
content: [
|
|
192
|
-
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
193
|
-
],
|
|
194
|
-
isError: result.isError,
|
|
195
|
-
};
|
|
196
|
-
});
|
|
197
|
-
// --- Geo tools ---
|
|
198
|
-
server.tool("geos_list", "List all available geographic regions for proxy targeting.", async () => {
|
|
199
|
-
const result = await tools.geosList();
|
|
200
|
-
return {
|
|
201
|
-
content: [
|
|
202
|
-
{ type: "text", text: JSON.stringify(result.data, null, 2) },
|
|
203
|
-
],
|
|
204
|
-
isError: result.isError,
|
|
205
|
-
};
|
|
206
|
-
});
|
|
207
|
-
// --- Start server ---
|
|
208
|
-
async function main() {
|
|
209
|
-
const transport = new stdio_js_1.StdioServerTransport();
|
|
210
|
-
await server.connect(transport);
|
|
211
|
-
console.error("Aluvia MCP server running on stdio");
|
|
212
|
-
}
|
|
213
|
-
// Only run when executed directly (not when imported for testing)
|
|
214
|
-
const isMcpServer = process.argv[1]?.match(/(?:mcp-server)\.[jt]s$/);
|
|
215
|
-
if (isMcpServer) {
|
|
216
|
-
main().catch((err) => {
|
|
217
|
-
console.error("Fatal error in MCP server:", err);
|
|
218
|
-
process.exit(1);
|
|
219
|
-
});
|
|
220
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* MCP tool implementations.
|
|
4
|
-
*
|
|
5
|
-
* Each tool wraps the corresponding CLI handler via captureOutput(),
|
|
6
|
-
* converting the handler's JSON output into MCP tool results.
|
|
7
|
-
*/
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.sessionStart = sessionStart;
|
|
10
|
-
exports.sessionClose = sessionClose;
|
|
11
|
-
exports.sessionList = sessionList;
|
|
12
|
-
exports.sessionGet = sessionGet;
|
|
13
|
-
exports.sessionRotateIp = sessionRotateIp;
|
|
14
|
-
exports.sessionSetGeo = sessionSetGeo;
|
|
15
|
-
exports.sessionSetRules = sessionSetRules;
|
|
16
|
-
exports.accountGet = accountGet;
|
|
17
|
-
exports.accountUsage = accountUsage;
|
|
18
|
-
exports.geosList = geosList;
|
|
19
|
-
const session_js_1 = require("./session.js");
|
|
20
|
-
const account_js_1 = require("./account.js");
|
|
21
|
-
const geos_js_1 = require("./geos.js");
|
|
22
|
-
const open_js_1 = require("./open.js");
|
|
23
|
-
const mcp_helpers_js_1 = require("./mcp-helpers.js");
|
|
24
|
-
async function sessionStart(args) {
|
|
25
|
-
return (0, mcp_helpers_js_1.captureOutput)(() => (0, open_js_1.handleOpen)({
|
|
26
|
-
url: args.url,
|
|
27
|
-
connectionId: args.connectionId,
|
|
28
|
-
headless: !args.headful,
|
|
29
|
-
sessionName: args.browserSession,
|
|
30
|
-
autoUnblock: args.autoUnblock,
|
|
31
|
-
disableBlockDetection: args.disableBlockDetection,
|
|
32
|
-
}));
|
|
33
|
-
}
|
|
34
|
-
async function sessionClose(args) {
|
|
35
|
-
const cliArgs = ["close"];
|
|
36
|
-
if (args.browserSession)
|
|
37
|
-
cliArgs.push("--browser-session", args.browserSession);
|
|
38
|
-
if (args.all)
|
|
39
|
-
cliArgs.push("--all");
|
|
40
|
-
return (0, mcp_helpers_js_1.captureOutput)(() => (0, session_js_1.handleSession)(cliArgs));
|
|
41
|
-
}
|
|
42
|
-
async function sessionList() {
|
|
43
|
-
return (0, mcp_helpers_js_1.captureOutput)(() => (0, session_js_1.handleSession)(["list"]));
|
|
44
|
-
}
|
|
45
|
-
async function sessionGet(args) {
|
|
46
|
-
const cliArgs = ["get"];
|
|
47
|
-
if (args.browserSession)
|
|
48
|
-
cliArgs.push("--browser-session", args.browserSession);
|
|
49
|
-
return (0, mcp_helpers_js_1.captureOutput)(() => (0, session_js_1.handleSession)(cliArgs));
|
|
50
|
-
}
|
|
51
|
-
async function sessionRotateIp(args) {
|
|
52
|
-
const cliArgs = ["rotate-ip"];
|
|
53
|
-
if (args.browserSession)
|
|
54
|
-
cliArgs.push("--browser-session", args.browserSession);
|
|
55
|
-
return (0, mcp_helpers_js_1.captureOutput)(() => (0, session_js_1.handleSession)(cliArgs));
|
|
56
|
-
}
|
|
57
|
-
async function sessionSetGeo(args) {
|
|
58
|
-
const cliArgs = ["set-geo"];
|
|
59
|
-
if (args.geo)
|
|
60
|
-
cliArgs.push(args.geo);
|
|
61
|
-
if (args.clear)
|
|
62
|
-
cliArgs.push("--clear");
|
|
63
|
-
if (args.browserSession)
|
|
64
|
-
cliArgs.push("--browser-session", args.browserSession);
|
|
65
|
-
return (0, mcp_helpers_js_1.captureOutput)(() => (0, session_js_1.handleSession)(cliArgs));
|
|
66
|
-
}
|
|
67
|
-
async function sessionSetRules(args) {
|
|
68
|
-
const cliArgs = ["set-rules"];
|
|
69
|
-
if (args.rules)
|
|
70
|
-
cliArgs.push(args.rules);
|
|
71
|
-
if (args.remove)
|
|
72
|
-
cliArgs.push("--remove", args.remove);
|
|
73
|
-
if (args.browserSession)
|
|
74
|
-
cliArgs.push("--browser-session", args.browserSession);
|
|
75
|
-
return (0, mcp_helpers_js_1.captureOutput)(() => (0, session_js_1.handleSession)(cliArgs));
|
|
76
|
-
}
|
|
77
|
-
async function accountGet() {
|
|
78
|
-
return (0, mcp_helpers_js_1.captureOutput)(() => (0, account_js_1.handleAccount)([]));
|
|
79
|
-
}
|
|
80
|
-
async function accountUsage(args) {
|
|
81
|
-
const cliArgs = ["usage"];
|
|
82
|
-
if (args.start)
|
|
83
|
-
cliArgs.push("--start", args.start);
|
|
84
|
-
if (args.end)
|
|
85
|
-
cliArgs.push("--end", args.end);
|
|
86
|
-
return (0, mcp_helpers_js_1.captureOutput)(() => (0, account_js_1.handleAccount)(cliArgs));
|
|
87
|
-
}
|
|
88
|
-
async function geosList() {
|
|
89
|
-
return (0, mcp_helpers_js_1.captureOutput)(() => (0, geos_js_1.handleGeos)());
|
|
90
|
-
}
|