alterlab-mcp-server 1.6.1 → 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.
- package/README.md +7 -7
- package/dist/auth.d.ts +30 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +423 -0
- package/dist/auth.js.map +1 -0
- package/dist/client.d.ts +22 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +56 -1
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +21 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +85 -8
- package/dist/config.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +28 -6
- package/dist/errors.js.map +1 -1
- package/dist/format.d.ts +16 -2
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +154 -10
- package/dist/format.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +63 -1
- package/dist/index.js.map +1 -1
- package/dist/tools/balance.d.ts.map +1 -1
- package/dist/tools/balance.js +4 -2
- package/dist/tools/balance.js.map +1 -1
- package/dist/tools/batch.d.ts +8 -8
- package/dist/tools/batch.d.ts.map +1 -1
- package/dist/tools/batch.js +3 -2
- package/dist/tools/batch.js.map +1 -1
- package/dist/tools/crawl.d.ts +41 -0
- package/dist/tools/crawl.d.ts.map +1 -1
- package/dist/tools/crawl.js +76 -7
- package/dist/tools/crawl.js.map +1 -1
- package/dist/tools/estimate.d.ts +1 -1
- package/dist/tools/estimate.d.ts.map +1 -1
- package/dist/tools/estimate.js +6 -4
- package/dist/tools/estimate.js.map +1 -1
- package/dist/tools/extract.d.ts +5 -5
- package/dist/tools/extract.d.ts.map +1 -1
- package/dist/tools/extract.js +14 -12
- package/dist/tools/extract.js.map +1 -1
- package/dist/tools/map.d.ts +5 -2
- package/dist/tools/map.d.ts.map +1 -1
- package/dist/tools/map.js +12 -4
- package/dist/tools/map.js.map +1 -1
- package/dist/tools/scrape.d.ts +91 -9
- package/dist/tools/scrape.d.ts.map +1 -1
- package/dist/tools/scrape.js +201 -24
- package/dist/tools/scrape.js.map +1 -1
- package/dist/tools/screenshot.d.ts.map +1 -1
- package/dist/tools/screenshot.js +16 -7
- package/dist/tools/screenshot.js.map +1 -1
- package/dist/tools/search.d.ts +3 -0
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +12 -4
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/simple_batch.d.ts +28 -0
- package/dist/tools/simple_batch.d.ts.map +1 -0
- package/dist/tools/simple_batch.js +141 -0
- package/dist/tools/simple_batch.js.map +1 -0
- package/dist/tools/usage.d.ts +7 -0
- package/dist/tools/usage.d.ts.map +1 -0
- package/dist/tools/usage.js +51 -0
- package/dist/tools/usage.js.map +1 -0
- package/dist/types.d.ts +99 -3
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/server.json +34 -2
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
|
|
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.
|
|
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
|
package/dist/auth.js.map
ADDED
|
@@ -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>;
|
package/dist/client.d.ts.map
CHANGED
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|