alterlab-mcp-server 1.7.0 → 1.8.0

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.
Files changed (70) hide show
  1. package/README.md +7 -7
  2. package/dist/auth.d.ts +30 -0
  3. package/dist/auth.d.ts.map +1 -0
  4. package/dist/auth.js +423 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/client.d.ts +22 -1
  7. package/dist/client.d.ts.map +1 -1
  8. package/dist/client.js +56 -1
  9. package/dist/client.js.map +1 -1
  10. package/dist/config.d.ts +21 -1
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js +85 -8
  13. package/dist/config.js.map +1 -1
  14. package/dist/errors.d.ts.map +1 -1
  15. package/dist/errors.js +6 -4
  16. package/dist/errors.js.map +1 -1
  17. package/dist/format.d.ts +16 -2
  18. package/dist/format.d.ts.map +1 -1
  19. package/dist/format.js +139 -9
  20. package/dist/format.js.map +1 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +63 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/tools/balance.d.ts.map +1 -1
  25. package/dist/tools/balance.js +4 -2
  26. package/dist/tools/balance.js.map +1 -1
  27. package/dist/tools/batch.d.ts +8 -8
  28. package/dist/tools/batch.d.ts.map +1 -1
  29. package/dist/tools/batch.js +3 -2
  30. package/dist/tools/batch.js.map +1 -1
  31. package/dist/tools/crawl.d.ts +38 -0
  32. package/dist/tools/crawl.d.ts.map +1 -1
  33. package/dist/tools/crawl.js +70 -7
  34. package/dist/tools/crawl.js.map +1 -1
  35. package/dist/tools/estimate.d.ts +1 -1
  36. package/dist/tools/estimate.d.ts.map +1 -1
  37. package/dist/tools/estimate.js +6 -4
  38. package/dist/tools/estimate.js.map +1 -1
  39. package/dist/tools/extract.d.ts +5 -5
  40. package/dist/tools/extract.d.ts.map +1 -1
  41. package/dist/tools/extract.js +14 -12
  42. package/dist/tools/extract.js.map +1 -1
  43. package/dist/tools/map.d.ts +5 -2
  44. package/dist/tools/map.d.ts.map +1 -1
  45. package/dist/tools/map.js +12 -4
  46. package/dist/tools/map.js.map +1 -1
  47. package/dist/tools/scrape.d.ts +88 -9
  48. package/dist/tools/scrape.d.ts.map +1 -1
  49. package/dist/tools/scrape.js +195 -24
  50. package/dist/tools/scrape.js.map +1 -1
  51. package/dist/tools/screenshot.d.ts.map +1 -1
  52. package/dist/tools/screenshot.js +16 -7
  53. package/dist/tools/screenshot.js.map +1 -1
  54. package/dist/tools/search.d.ts +3 -0
  55. package/dist/tools/search.d.ts.map +1 -1
  56. package/dist/tools/search.js +12 -4
  57. package/dist/tools/search.js.map +1 -1
  58. package/dist/tools/simple_batch.d.ts +28 -0
  59. package/dist/tools/simple_batch.d.ts.map +1 -0
  60. package/dist/tools/simple_batch.js +141 -0
  61. package/dist/tools/simple_batch.js.map +1 -0
  62. package/dist/tools/usage.d.ts +7 -0
  63. package/dist/tools/usage.d.ts.map +1 -0
  64. package/dist/tools/usage.js +51 -0
  65. package/dist/tools/usage.js.map +1 -0
  66. package/dist/types.d.ts +83 -3
  67. package/dist/types.d.ts.map +1 -1
  68. package/dist/types.js.map +1 -1
  69. package/package.json +1 -1
  70. package/server.json +32 -0
package/README.md CHANGED
@@ -26,7 +26,7 @@
26
26
  ### Claude Code
27
27
 
28
28
  ```bash
29
- claude mcp add alterlab -- npx -y alterlab-mcp-server
29
+ claude mcp add alterlab -- npx -y alterlab-mcp-server@latest
30
30
  ```
31
31
 
32
32
  Then set your API key: `export ALTERLAB_API_KEY=sk_live_...` or add it to `.claude.json` (see [full setup](#install-in-claude-desktop--claude-code) below).
@@ -87,7 +87,7 @@ Add to your Claude config file (`~/.claude.json` for Claude Code, or Settings fo
87
87
  "mcpServers": {
88
88
  "alterlab": {
89
89
  "command": "npx",
90
- "args": ["-y", "alterlab-mcp-server"],
90
+ "args": ["-y", "alterlab-mcp-server@latest"],
91
91
  "env": {
92
92
  "ALTERLAB_API_KEY": "sk_live_your_key_here"
93
93
  }
@@ -105,7 +105,7 @@ Add to `.cursor/mcp.json` in your project root:
105
105
  "mcpServers": {
106
106
  "alterlab": {
107
107
  "command": "npx",
108
- "args": ["-y", "alterlab-mcp-server"],
108
+ "args": ["-y", "alterlab-mcp-server@latest"],
109
109
  "env": {
110
110
  "ALTERLAB_API_KEY": "sk_live_your_key_here"
111
111
  }
@@ -123,7 +123,7 @@ Add to Windsurf MCP settings (`~/.codeium/windsurf/mcp_config.json`):
123
123
  "mcpServers": {
124
124
  "alterlab": {
125
125
  "command": "npx",
126
- "args": ["-y", "alterlab-mcp-server"],
126
+ "args": ["-y", "alterlab-mcp-server@latest"],
127
127
  "env": {
128
128
  "ALTERLAB_API_KEY": "sk_live_your_key_here"
129
129
  }
@@ -385,7 +385,7 @@ No subscriptions. No monthly minimums. Add balance and use it whenever you need
385
385
 
386
386
  ### How do I add web scraping to Claude, Cursor, or Windsurf?
387
387
 
388
- Install the AlterLab MCP server. For Claude Code, run `claude mcp add alterlab -- npx -y alterlab-mcp-server` and set your `ALTERLAB_API_KEY`. For Claude Desktop, Cursor, or Windsurf, add the JSON config block to your MCP settings file. Once configured, your AI assistant can scrape any URL, extract structured data, and take screenshots directly in conversation.
388
+ Install the AlterLab MCP server. For Claude Code, run `claude mcp add alterlab -- npx -y alterlab-mcp-server@latest` and set your `ALTERLAB_API_KEY`. For Claude Desktop, Cursor, or Windsurf, add the JSON config block to your MCP settings file. Once configured, your AI assistant can scrape any URL, extract structured data, and take screenshots directly in conversation.
389
389
 
390
390
  ### Can Claude scrape websites that are behind Cloudflare or anti-bot protection?
391
391
 
@@ -393,7 +393,7 @@ Yes. AlterLab automatically handles Cloudflare, DataDome, PerimeterX, Akamai, an
393
393
 
394
394
  ### What is an MCP server and how does it work with Claude?
395
395
 
396
- MCP (Model Context Protocol) is Anthropic's open standard for connecting AI assistants to external tools and data sources. An MCP server is a small program that exposes tools — like web scraping — that Claude, Cursor, or Windsurf can call during a conversation. The AlterLab MCP server gives your AI assistant 5 tools: scrape, extract, screenshot, estimate cost, and check balance.
396
+ MCP (Model Context Protocol) is Anthropic's open standard for connecting AI assistants to external tools and data sources. An MCP server is a small program that exposes tools — like web scraping — that Claude, Cursor, or Windsurf can call during a conversation. The AlterLab MCP server gives your AI assistant 23 tools: scrape, extract, screenshot, crawl, search, map, batch scraping, session management, beta features, and more.
397
397
 
398
398
  ### How is AlterLab different from Firecrawl, ScrapingBee, or Apify MCP servers?
399
399
 
@@ -421,7 +421,7 @@ Free-tier accounts have rate limits. Adding any balance removes rate limits. The
421
421
 
422
422
  ### Can I use this MCP server for large-scale scraping?
423
423
 
424
- Yes. The MCP server processes one request at a time through the conversation interface, but you can build agentic workflows that scrape many URLs sequentially. For batch processing, use the AlterLab API directly or the [n8n integration](https://www.npmjs.com/package/n8n-nodes-alterlab).
424
+ Yes. For parallel scraping, use `alterlab_batch` to scrape up to 100 URLs in a single request — much faster than sequential calls. For crawling entire domains, use `alterlab_crawl`. You can also build agentic workflows that scrape many URLs sequentially, or use the [n8n integration](https://www.npmjs.com/package/n8n-nodes-alterlab) for workflow automation.
425
425
 
426
426
  ---
427
427
 
package/dist/auth.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * OAuth 2.0 Device Authorization Grant (RFC 8628) client-side flow.
3
+ *
4
+ * Authentication priority chain:
5
+ * 1. ALTERLAB_API_KEY environment variable
6
+ * 2. ~/.alterlab/config.json
7
+ * 3. Interactive auth (TTY only):
8
+ * a. 5-second countdown — press any key to switch to manual paste
9
+ * b. Device flow (POST /auth/device → open browser → poll /auth/token)
10
+ * c. Fallback: manual API key paste
11
+ *
12
+ * All user-facing output goes to stderr — stdout is reserved for MCP protocol.
13
+ */
14
+ import { type Config } from "./config.js";
15
+ /**
16
+ * Ensure a valid AlterLab API key is available and return a Config object.
17
+ *
18
+ * Resolution order:
19
+ * 1. ALTERLAB_API_KEY environment variable
20
+ * 2. ~/.alterlab/config.json
21
+ * 3. Interactive auth (only when running in a TTY):
22
+ * a. 5-second countdown — press any key to switch to manual paste
23
+ * b. OAuth 2.0 Device Authorization Grant flow (if countdown expires)
24
+ * c. Manual API key paste (if keypress during countdown, or device flow fails)
25
+ *
26
+ * When not running in a TTY (e.g., as an MCP server subprocess), emits a
27
+ * helpful error on stderr and exits with code 1 if no key is found.
28
+ */
29
+ export declare function ensureAuth(): Promise<Config>;
30
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAMH,OAAO,EACL,KAAK,MAAM,EAKZ,MAAM,aAAa,CAAC;AAuXrB;;;;;;;;;;;;;GAaG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CA0FlD"}
package/dist/auth.js ADDED
@@ -0,0 +1,423 @@
1
+ "use strict";
2
+ /**
3
+ * OAuth 2.0 Device Authorization Grant (RFC 8628) client-side flow.
4
+ *
5
+ * Authentication priority chain:
6
+ * 1. ALTERLAB_API_KEY environment variable
7
+ * 2. ~/.alterlab/config.json
8
+ * 3. Interactive auth (TTY only):
9
+ * a. 5-second countdown — press any key to switch to manual paste
10
+ * b. Device flow (POST /auth/device → open browser → poll /auth/token)
11
+ * c. Fallback: manual API key paste
12
+ *
13
+ * All user-facing output goes to stderr — stdout is reserved for MCP protocol.
14
+ */
15
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ var desc = Object.getOwnPropertyDescriptor(m, k);
18
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
19
+ desc = { enumerable: true, get: function() { return m[k]; } };
20
+ }
21
+ Object.defineProperty(o, k2, desc);
22
+ }) : (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ o[k2] = m[k];
25
+ }));
26
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
27
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
28
+ }) : function(o, v) {
29
+ o["default"] = v;
30
+ });
31
+ var __importStar = (this && this.__importStar) || (function () {
32
+ var ownKeys = function(o) {
33
+ ownKeys = Object.getOwnPropertyNames || function (o) {
34
+ var ar = [];
35
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
36
+ return ar;
37
+ };
38
+ return ownKeys(o);
39
+ };
40
+ return function (mod) {
41
+ if (mod && mod.__esModule) return mod;
42
+ var result = {};
43
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
44
+ __setModuleDefault(result, mod);
45
+ return result;
46
+ };
47
+ })();
48
+ Object.defineProperty(exports, "__esModule", { value: true });
49
+ exports.ensureAuth = ensureAuth;
50
+ const https = __importStar(require("https"));
51
+ const http = __importStar(require("http"));
52
+ const readline = __importStar(require("readline"));
53
+ const child_process_1 = require("child_process");
54
+ const config_js_1 = require("./config.js");
55
+ // ---------------------------------------------------------------------------
56
+ // HTTP helper — wraps Node's built-in https/http for simple JSON requests
57
+ // ---------------------------------------------------------------------------
58
+ function postJson(url, body) {
59
+ return new Promise((resolve, reject) => {
60
+ const payload = JSON.stringify(body);
61
+ const parsed = new URL(url);
62
+ const options = {
63
+ hostname: parsed.hostname,
64
+ port: parsed.port || (parsed.protocol === "https:" ? 443 : 80),
65
+ path: parsed.pathname + parsed.search,
66
+ method: "POST",
67
+ headers: {
68
+ "Content-Type": "application/json",
69
+ "Content-Length": Buffer.byteLength(payload),
70
+ "User-Agent": "alterlab-mcp-server",
71
+ Accept: "application/json",
72
+ },
73
+ };
74
+ const transport = parsed.protocol === "https:" ? https : http;
75
+ const req = transport.request(options, (res) => {
76
+ let raw = "";
77
+ res.on("data", (chunk) => {
78
+ raw += chunk.toString();
79
+ });
80
+ res.on("end", () => {
81
+ try {
82
+ resolve({ status: res.statusCode ?? 0, data: JSON.parse(raw) });
83
+ }
84
+ catch {
85
+ resolve({ status: res.statusCode ?? 0, data: raw });
86
+ }
87
+ });
88
+ });
89
+ req.on("error", reject);
90
+ req.setTimeout(15_000, () => {
91
+ req.destroy(new Error("Request timed out"));
92
+ });
93
+ req.write(payload);
94
+ req.end();
95
+ });
96
+ }
97
+ // ---------------------------------------------------------------------------
98
+ // Browser launcher
99
+ // ---------------------------------------------------------------------------
100
+ function openBrowser(url) {
101
+ // Validate URL before passing to shell — accept only http(s) schemes to
102
+ // prevent shell injection if the device server returns a malicious URL.
103
+ let parsed;
104
+ try {
105
+ parsed = new URL(url);
106
+ }
107
+ catch {
108
+ process.stderr.write(` (Could not parse browser URL — copy and open manually)\n`);
109
+ return;
110
+ }
111
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
112
+ process.stderr.write(` (Unexpected URL scheme '${parsed.protocol}' — skipping auto-open)\n`);
113
+ return;
114
+ }
115
+ // Use execFile (not exec) to avoid shell interpretation of the URL.
116
+ // The URL is passed as a standalone argument — no shell quoting needed.
117
+ const platform = process.platform;
118
+ let bin;
119
+ if (platform === "win32") {
120
+ bin = "cmd";
121
+ }
122
+ else if (platform === "darwin") {
123
+ bin = "open";
124
+ }
125
+ else {
126
+ bin = "xdg-open";
127
+ }
128
+ const args = platform === "win32" ? ["/c", "start", "", url] : [url];
129
+ (0, child_process_1.execFile)(bin, args, () => {
130
+ // Ignore errors — if the browser doesn't open, the user can copy the URL
131
+ });
132
+ }
133
+ // ---------------------------------------------------------------------------
134
+ // Device flow
135
+ // ---------------------------------------------------------------------------
136
+ async function runDeviceFlow(apiUrl) {
137
+ process.stderr.write("\n Attempting device authorization flow...\n");
138
+ // Step 1: Request device & user codes
139
+ let deviceResp;
140
+ try {
141
+ deviceResp = await postJson(`${apiUrl}/auth/device`, {
142
+ client_id: "alterlab-mcp-server",
143
+ scope: "api_key:create",
144
+ });
145
+ }
146
+ catch (err) {
147
+ process.stderr.write(` Device flow unavailable (network error: ${String(err)})\n`);
148
+ return null;
149
+ }
150
+ if (deviceResp.status === 404) {
151
+ // Backend endpoints not yet live — caller will fall back to manual paste
152
+ process.stderr.write(" Device flow not yet available on this server — falling back to manual entry.\n");
153
+ return null;
154
+ }
155
+ if (deviceResp.status !== 200) {
156
+ process.stderr.write(` Device flow returned unexpected status ${deviceResp.status} — falling back to manual entry.\n`);
157
+ return null;
158
+ }
159
+ const device = deviceResp.data;
160
+ if (!device.device_code || !device.user_code || !device.verification_url) {
161
+ process.stderr.write(" Device flow response missing required fields — falling back to manual entry.\n");
162
+ return null;
163
+ }
164
+ // Step 2: Show the user what to do
165
+ const verifyUrl = device.verification_url_complete ?? device.verification_url;
166
+ process.stderr.write([
167
+ "",
168
+ " ── AlterLab Authentication ─────────────────────────────",
169
+ ` Open this link to authenticate:`,
170
+ ` ${verifyUrl}`,
171
+ "",
172
+ ` Your device code: ${device.user_code}`,
173
+ " ──────────────────────────────────────────────────────────",
174
+ "",
175
+ ].join("\n"));
176
+ // Step 3: Open browser automatically
177
+ openBrowser(verifyUrl);
178
+ // Step 4: Poll /auth/token until success, expiry, or error
179
+ const pollInterval = Math.max((device.interval ?? 5) * 1_000, 5_000);
180
+ const expiresAt = Date.now() + (device.expires_in ?? 900) * 1_000;
181
+ process.stderr.write(" Waiting for authentication");
182
+ while (Date.now() < expiresAt) {
183
+ await new Promise((r) => setTimeout(r, pollInterval));
184
+ process.stderr.write(".");
185
+ let tokenResp;
186
+ try {
187
+ tokenResp = await postJson(`${apiUrl}/auth/token`, {
188
+ client_id: "alterlab-mcp-server",
189
+ device_code: device.device_code,
190
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code",
191
+ });
192
+ }
193
+ catch {
194
+ // Network hiccup — keep polling
195
+ continue;
196
+ }
197
+ const tokenData = tokenResp.data;
198
+ if (tokenResp.status === 200 && "api_key" in tokenData) {
199
+ process.stderr.write(" ✓\n\n");
200
+ return tokenData.api_key;
201
+ }
202
+ if ("error" in tokenData) {
203
+ const err = tokenData.error;
204
+ if (err === "authorization_pending") {
205
+ continue;
206
+ }
207
+ if (err === "slow_down") {
208
+ await new Promise((r) => setTimeout(r, pollInterval));
209
+ continue;
210
+ }
211
+ // expired_token, access_denied, or unknown error
212
+ process.stderr.write(`\n Authentication failed: ${err}\n`);
213
+ return null;
214
+ }
215
+ }
216
+ process.stderr.write("\n Authentication timed out.\n");
217
+ return null;
218
+ }
219
+ // ---------------------------------------------------------------------------
220
+ // Manual paste fallback
221
+ // ---------------------------------------------------------------------------
222
+ function promptForApiKey() {
223
+ return new Promise((resolve) => {
224
+ const rl = readline.createInterface({
225
+ input: process.stdin,
226
+ output: process.stderr, // write prompt to stderr
227
+ terminal: false,
228
+ });
229
+ process.stderr.write([
230
+ "",
231
+ " ── AlterLab API Key Setup ─────────────────────────────",
232
+ " Get your API key at: https://alterlab.io/dashboard/api-keys",
233
+ "",
234
+ " Paste your API key: ",
235
+ ].join("\n"));
236
+ rl.once("line", (line) => {
237
+ rl.close();
238
+ resolve(line.trim());
239
+ });
240
+ });
241
+ }
242
+ // ---------------------------------------------------------------------------
243
+ // Countdown with keypress detection
244
+ // ---------------------------------------------------------------------------
245
+ /**
246
+ * Display a countdown on stderr and return true if the user presses a key
247
+ * before the timeout expires, or false if the timeout expires with no input.
248
+ *
249
+ * Uses raw mode stdin so that a single keypress (no Enter required) is enough
250
+ * to interrupt the countdown. stdin is always restored to non-raw mode inside
251
+ * finish() before the promise resolves.
252
+ *
253
+ * Safe to call only when process.stdin.isTTY is true — setRawMode is not
254
+ * available in non-TTY contexts and will throw otherwise.
255
+ *
256
+ * @param timeoutMs - Total countdown duration in milliseconds (default 5000)
257
+ * @returns true if keypress detected before timeout, false if timeout expired
258
+ */
259
+ async function waitForKeypressOrTimeout(timeoutMs = 5_000) {
260
+ const TICK_MS = 100; // update interval for progress display
261
+ const BAR_WIDTH = 10; // width of the progress bar in characters
262
+ let keypressDetected = false;
263
+ // Enable raw mode so we receive individual keypresses without Enter.
264
+ // Guard with isTTY (caller must also check) and a try/catch in case the
265
+ // terminal does not support raw mode (e.g., some CI pseudo-TTYs).
266
+ let rawModeEnabled = false;
267
+ try {
268
+ process.stdin.setRawMode(true);
269
+ rawModeEnabled = true;
270
+ }
271
+ catch {
272
+ // setRawMode unavailable — fall through without keypress detection.
273
+ // The countdown will still display and expire normally.
274
+ }
275
+ return new Promise((resolve) => {
276
+ let ticksDone = 0;
277
+ let resolved = false;
278
+ const finish = (pressed) => {
279
+ if (resolved)
280
+ return;
281
+ resolved = true;
282
+ // Clear the countdown line from stderr
283
+ process.stderr.write("\r\x1b[K");
284
+ // Restore stdin before resolving
285
+ try {
286
+ if (rawModeEnabled) {
287
+ process.stdin.setRawMode(false);
288
+ }
289
+ process.stdin.pause();
290
+ }
291
+ catch {
292
+ // ignore cleanup errors
293
+ }
294
+ keypressDetected = pressed;
295
+ resolve(pressed);
296
+ };
297
+ // Keypress handler — any key press interrupts the countdown
298
+ const onData = (_chunk) => {
299
+ finish(true);
300
+ };
301
+ if (rawModeEnabled) {
302
+ process.stdin.resume();
303
+ process.stdin.once("data", onData);
304
+ }
305
+ // Tick function — renders the countdown progress bar on stderr
306
+ const tick = () => {
307
+ if (resolved)
308
+ return;
309
+ ticksDone += 1;
310
+ const elapsed = ticksDone * TICK_MS;
311
+ const remaining = Math.max(0, timeoutMs - elapsed);
312
+ const remainingSeconds = Math.ceil(remaining / 1_000);
313
+ const filled = Math.round((elapsed / timeoutMs) * BAR_WIDTH);
314
+ const empty = BAR_WIDTH - filled;
315
+ const bar = "█".repeat(filled) + "░".repeat(empty);
316
+ process.stderr.write(`\r [${bar}] ${remainingSeconds}s — press any key to enter an existing key instead`);
317
+ if (elapsed >= timeoutMs) {
318
+ if (rawModeEnabled) {
319
+ process.stdin.removeListener("data", onData);
320
+ }
321
+ finish(false);
322
+ }
323
+ else {
324
+ setTimeout(tick, TICK_MS);
325
+ }
326
+ };
327
+ // Initial render before first tick
328
+ const bar0 = "░".repeat(BAR_WIDTH);
329
+ const secs0 = Math.ceil(timeoutMs / 1_000);
330
+ process.stderr.write(`\r [${bar0}] ${secs0}s — press any key to enter an existing key instead`);
331
+ setTimeout(tick, TICK_MS);
332
+ });
333
+ }
334
+ // ---------------------------------------------------------------------------
335
+ // Main exported function
336
+ // ---------------------------------------------------------------------------
337
+ /**
338
+ * Ensure a valid AlterLab API key is available and return a Config object.
339
+ *
340
+ * Resolution order:
341
+ * 1. ALTERLAB_API_KEY environment variable
342
+ * 2. ~/.alterlab/config.json
343
+ * 3. Interactive auth (only when running in a TTY):
344
+ * a. 5-second countdown — press any key to switch to manual paste
345
+ * b. OAuth 2.0 Device Authorization Grant flow (if countdown expires)
346
+ * c. Manual API key paste (if keypress during countdown, or device flow fails)
347
+ *
348
+ * When not running in a TTY (e.g., as an MCP server subprocess), emits a
349
+ * helpful error on stderr and exits with code 1 if no key is found.
350
+ */
351
+ async function ensureAuth() {
352
+ // 1. Environment variable (highest priority — existing behavior)
353
+ const envConfig = (0, config_js_1.loadConfig)();
354
+ if (envConfig) {
355
+ return envConfig;
356
+ }
357
+ // 2. Config file
358
+ const fileConfig = (0, config_js_1.loadConfigFromFile)();
359
+ if (fileConfig) {
360
+ return fileConfig;
361
+ }
362
+ const apiUrl = (0, config_js_1.getApiUrl)();
363
+ // 3. Interactive auth — only possible in a TTY
364
+ if (!process.stdin.isTTY) {
365
+ process.stderr.write([
366
+ "",
367
+ " Error: No API key found for AlterLab MCP Server.",
368
+ "",
369
+ " Add your API key to your MCP client config:",
370
+ ' "env": { "ALTERLAB_API_KEY": "sk_live_..." }',
371
+ "",
372
+ " Or run the server interactively once to authenticate:",
373
+ " npx -y alterlab-mcp-server",
374
+ "",
375
+ " Get your API key at: https://alterlab.io/dashboard/api-keys",
376
+ "",
377
+ ].join("\n"));
378
+ process.exit(1);
379
+ }
380
+ // Running interactively — show welcome banner
381
+ process.stderr.write([
382
+ "",
383
+ " ╔══════════════════════════════════════════════════════╗",
384
+ " ║ AlterLab MCP Server — First Run Setup ║",
385
+ " ╚══════════════════════════════════════════════════════╝",
386
+ "",
387
+ " No API key found. Let's get you authenticated.",
388
+ "",
389
+ " → A browser will open to authenticate in 5 seconds...",
390
+ "",
391
+ ].join("\n"));
392
+ // 3a. 5-second countdown — lets the user interrupt before device flow starts
393
+ const userPressedKey = await waitForKeypressOrTimeout(5_000);
394
+ let apiKey = null;
395
+ if (userPressedKey) {
396
+ // User pressed a key — skip device flow, go straight to manual paste
397
+ process.stderr.write(" (Switching to manual key entry)\n\n");
398
+ apiKey = await promptForApiKey();
399
+ }
400
+ else {
401
+ // Countdown expired — attempt device flow
402
+ const deviceApiKey = await runDeviceFlow(apiUrl);
403
+ apiKey = deviceApiKey;
404
+ // 3b. Fallback to manual paste if device flow failed or unavailable
405
+ if (!apiKey) {
406
+ apiKey = await promptForApiKey();
407
+ }
408
+ }
409
+ if (!apiKey) {
410
+ process.stderr.write("\n Error: No API key provided. Exiting.\n\n");
411
+ process.exit(1);
412
+ }
413
+ // Persist for future runs
414
+ try {
415
+ (0, config_js_1.saveConfigToFile)(apiKey);
416
+ process.stderr.write(` ✓ API key saved to ~/.alterlab/config.json\n\n`);
417
+ }
418
+ catch (err) {
419
+ process.stderr.write(` Warning: Could not save config file: ${String(err)}\n`);
420
+ }
421
+ return { apiKey, apiUrl };
422
+ }
423
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/client.d.ts CHANGED
@@ -1,14 +1,35 @@
1
1
  import { type Config } from "./config.js";
2
- import { type BalanceResponse, type BatchRequest, type BatchResponse, type BatchStatusResponse, type BetaFeatureListResponse, type BetaFeatureMyResponse, type BetaFeatureToggleResponse, type CostEstimate, type CrawlCancelResponse, type CrawlRequest, type CrawlResponse, type CrawlStatusResponse, type ExtractRequest, type ExtractResponse, type MapRequest, type MapResponse, type SearchRequest, type SearchResponse, type SessionCreateRequest, type SessionCreateResponse, type SessionDetailResponse, type SessionListResponse, type SessionRefreshRequest, type SessionUpdateRequest, type SessionValidateResponse, type UnifiedScrapeRequest, type UnifiedScrapeResponse } from "./types.js";
2
+ import { type BalanceResponse, type BalanceWarning, type BatchRequest, type BatchResponse, type BatchStatusResponse, type BetaFeatureListResponse, type BetaFeatureMyResponse, type BetaFeatureToggleResponse, type CostEstimate, type CrawlCancelResponse, type CrawlRequest, type CrawlResponse, type CrawlStatusResponse, type ExtractRequest, type ExtractResponse, type MapRequest, type MapResponse, type SearchRequest, type SearchResponse, type SessionCreateRequest, type SessionCreateResponse, type SessionDetailResponse, type SessionListResponse, type SessionRefreshRequest, type SessionUpdateRequest, type SessionValidateResponse, type UnifiedScrapeRequest, type UnifiedScrapeResponse, type UsageResponse } from "./types.js";
3
3
  export declare class AlterLabClient {
4
4
  private apiKey;
5
5
  private apiUrl;
6
6
  private userAgent;
7
+ private sourceHeader;
8
+ /**
9
+ * Stores the most recent balance warning parsed from response headers.
10
+ * Updated after every successful API call. Null when no warning headers
11
+ * were present in the last response, or before the first call.
12
+ */
13
+ private _lastBalanceWarning;
7
14
  constructor(config: Config);
15
+ /**
16
+ * Returns the balance warning from the most recent API response, or null
17
+ * if no warning headers were present. Tool handlers call this after each
18
+ * API request to append a proactive warning when balance is low.
19
+ */
20
+ getLastBalanceWarning(): BalanceWarning | null;
21
+ /**
22
+ * Parse X-AlterLab-Balance and X-AlterLab-Balance-Warning headers from an
23
+ * HTTP response and store the result. Both headers must be present and the
24
+ * warning level must be 'low', 'critical', or 'exhausted' — otherwise the
25
+ * stored warning is cleared to null (healthy balance = no warning).
26
+ */
27
+ private parseBalanceWarningHeaders;
8
28
  private request;
9
29
  scrape(params: UnifiedScrapeRequest): Promise<UnifiedScrapeResponse>;
10
30
  estimate(params: UnifiedScrapeRequest): Promise<CostEstimate>;
11
31
  getBalance(): Promise<BalanceResponse>;
32
+ getUsage(): Promise<UsageResponse>;
12
33
  listSessions(): Promise<SessionListResponse>;
13
34
  createSession(params: SessionCreateRequest): Promise<SessionCreateResponse>;
14
35
  validateSession(sessionId: string): Promise<SessionValidateResponse>;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC9B,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,cAAc,EAEnB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC3B,MAAM,YAAY,CAAC;AAOpB,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,EAAE,MAAM;YAMZ,OAAO;IAkDf,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAQpE,QAAQ,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,YAAY,CAAC;IAQ7D,UAAU,IAAI,OAAO,CAAC,eAAe,CAAC;IAItC,YAAY,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAI5C,aAAa,CACjB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,qBAAqB,CAAC;IAQ3B,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAOpE,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAO7D,aAAa,CACjB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,qBAAqB,CAAC;IAQ3B,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAQ3B,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAW/D,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAIxD,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI7D,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAW1D,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAQtD,GAAG,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;IAQ7C,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAQzD,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAIzD,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAQ7D,gBAAgB,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAOpD,kBAAkB,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAOpD,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAOnE,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAWpE,uBAAuB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAsBtE"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC9B,KAAK,YAAY,EACjB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,UAAU,EACf,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,cAAc,EAEnB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAOpB,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,YAAY,CAAS;IAE7B;;;;OAIG;IACH,OAAO,CAAC,mBAAmB,CAA+B;gBAE9C,MAAM,EAAE,MAAM;IAO1B;;;;OAIG;IACH,qBAAqB,IAAI,cAAc,GAAG,IAAI;IAI9C;;;;;OAKG;IACH,OAAO,CAAC,0BAA0B;YA4BpB,OAAO;IA0Df,MAAM,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAQpE,QAAQ,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,YAAY,CAAC;IAQ7D,UAAU,IAAI,OAAO,CAAC,eAAe,CAAC;IAItC,QAAQ,IAAI,OAAO,CAAC,aAAa,CAAC;IAIlC,YAAY,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAI5C,aAAa,CACjB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,qBAAqB,CAAC;IAQ3B,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAOpE,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAO7D,aAAa,CACjB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,qBAAqB,CAAC;IAQ3B,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,qBAAqB,GAC5B,OAAO,CAAC,qBAAqB,CAAC;IAQ3B,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;IAW/D,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAIxD,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAI7D,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAW1D,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAQtD,GAAG,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;IAQ7C,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;IAQzD,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAIzD,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAQ7D,gBAAgB,IAAI,OAAO,CAAC,uBAAuB,CAAC;IAOpD,kBAAkB,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAOpD,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAOnE,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAWpE,uBAAuB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAuBtE"}