amplitude-cli 0.3.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 +123 -0
- package/dist/commands/auth.d.ts +6 -0
- package/dist/commands/auth.js +133 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/charts.d.ts +6 -0
- package/dist/commands/charts.js +136 -0
- package/dist/commands/charts.js.map +1 -0
- package/dist/commands/cohorts.d.ts +6 -0
- package/dist/commands/cohorts.js +79 -0
- package/dist/commands/cohorts.js.map +1 -0
- package/dist/commands/dashboards.d.ts +6 -0
- package/dist/commands/dashboards.js +76 -0
- package/dist/commands/dashboards.js.map +1 -0
- package/dist/commands/events.d.ts +6 -0
- package/dist/commands/events.js +46 -0
- package/dist/commands/events.js.map +1 -0
- package/dist/commands/experiments.d.ts +6 -0
- package/dist/commands/experiments.js +57 -0
- package/dist/commands/experiments.js.map +1 -0
- package/dist/commands/query.d.ts +6 -0
- package/dist/commands/query.js +227 -0
- package/dist/commands/query.js.map +1 -0
- package/dist/commands/users.d.ts +6 -0
- package/dist/commands/users.js +49 -0
- package/dist/commands/users.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-client.d.ts +90 -0
- package/dist/mcp-client.js +291 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/utils/errors.d.ts +4 -0
- package/dist/utils/errors.js +34 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/format.d.ts +10 -0
- package/dist/utils/format.js +90 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/utils/mcp-helpers.d.ts +13 -0
- package/dist/utils/mcp-helpers.js +49 -0
- package/dist/utils/mcp-helpers.js.map +1 -0
- package/dist/utils/oauth.d.ts +62 -0
- package/dist/utils/oauth.js +344 -0
- package/dist/utils/oauth.js.map +1 -0
- package/package.json +30 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth 2.0 utilities for Amplitude MCP server.
|
|
3
|
+
* Handles:
|
|
4
|
+
* - Dynamic client registration
|
|
5
|
+
* - Authorization code flow with PKCE (S256)
|
|
6
|
+
* - Token storage and refresh
|
|
7
|
+
* - Local callback server
|
|
8
|
+
*/
|
|
9
|
+
import { createServer } from "node:http";
|
|
10
|
+
import { randomBytes, createHash } from "node:crypto";
|
|
11
|
+
import { readFileSync, writeFileSync, chmodSync } from "node:fs";
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import { homedir } from "node:os";
|
|
14
|
+
const MCP_REGIONS = {
|
|
15
|
+
us: "https://mcp.amplitude.com",
|
|
16
|
+
eu: "https://mcp.eu.amplitude.com",
|
|
17
|
+
};
|
|
18
|
+
const CALLBACK_PORT = 8900;
|
|
19
|
+
const CALLBACK_PATH = "/callback";
|
|
20
|
+
const SCOPES = "mcp:read mcp:write offline_access";
|
|
21
|
+
function configPath() {
|
|
22
|
+
return join(homedir(), ".amplituderc");
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Read the full config file (may contain apiKey/secretKey AND/OR oauth).
|
|
26
|
+
*/
|
|
27
|
+
export function readConfig() {
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(readFileSync(configPath(), "utf-8"));
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return {};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Write config, preserving existing fields.
|
|
37
|
+
*/
|
|
38
|
+
export function writeConfig(updates) {
|
|
39
|
+
const existing = readConfig();
|
|
40
|
+
const merged = { ...existing, ...updates };
|
|
41
|
+
writeFileSync(configPath(), JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
42
|
+
chmodSync(configPath(), 0o600);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Get stored OAuth tokens if they exist.
|
|
46
|
+
*/
|
|
47
|
+
export function getOAuthConfig() {
|
|
48
|
+
const config = readConfig();
|
|
49
|
+
if (config.oauth && typeof config.oauth === "object") {
|
|
50
|
+
return config.oauth;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Check if an OAuth token is available from any source.
|
|
56
|
+
* Does NOT throw — returns true/false.
|
|
57
|
+
*/
|
|
58
|
+
export function hasOAuthToken() {
|
|
59
|
+
if (process.env.AMPLITUDE_ACCESS_TOKEN || process.env.AMPLITUDE_OAUTH_TOKEN)
|
|
60
|
+
return true;
|
|
61
|
+
const oauth = getOAuthConfig();
|
|
62
|
+
return !!(oauth?.tokens?.access_token);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Get a valid access token. Checks sources in order:
|
|
66
|
+
* 1. AMPLITUDE_ACCESS_TOKEN (or AMPLITUDE_OAUTH_TOKEN) env var (injected by OpenClaw/Masterclaw via Nango)
|
|
67
|
+
* 2. AMPLITUDE_OAUTH_REFRESH_TOKEN env var (for auto-refresh via env)
|
|
68
|
+
* 3. ~/.amplituderc oauth config (from `amp auth login`)
|
|
69
|
+
*
|
|
70
|
+
* Env vars take priority — this is the managed-environment path where
|
|
71
|
+
* Masterclaw handles OAuth via Nango and injects tokens through
|
|
72
|
+
* openclaw.json → skills.entries.amplitude.env.
|
|
73
|
+
*/
|
|
74
|
+
export async function getAccessToken(region = "us") {
|
|
75
|
+
// 1. Check env var (managed environment — Masterclaw/Nango injects this)
|
|
76
|
+
const envToken = process.env.AMPLITUDE_ACCESS_TOKEN || process.env.AMPLITUDE_OAUTH_TOKEN;
|
|
77
|
+
if (envToken) {
|
|
78
|
+
return envToken;
|
|
79
|
+
}
|
|
80
|
+
// 2. Check config file (self-serve — `amp auth login`)
|
|
81
|
+
const oauth = getOAuthConfig();
|
|
82
|
+
if (!oauth?.tokens?.access_token) {
|
|
83
|
+
throw new Error("Not logged in. Run 'amp auth login' to authenticate with Amplitude.");
|
|
84
|
+
}
|
|
85
|
+
// Check if token is expired (with 60s buffer)
|
|
86
|
+
if (oauth.tokens.expires_at && Date.now() > oauth.tokens.expires_at - 60_000) {
|
|
87
|
+
// Try env refresh token first (managed environment may provide this)
|
|
88
|
+
const envRefresh = process.env.AMPLITUDE_OAUTH_REFRESH_TOKEN;
|
|
89
|
+
const refreshToken = envRefresh || oauth.tokens.refresh_token;
|
|
90
|
+
if (!refreshToken) {
|
|
91
|
+
throw new Error("Access token expired and no refresh token available. Run 'amp auth login' again.");
|
|
92
|
+
}
|
|
93
|
+
console.error("Access token expired, refreshing...");
|
|
94
|
+
const newTokens = await refreshTokens(oauth.client_id, refreshToken, region);
|
|
95
|
+
// Save refreshed tokens (only to file, not env)
|
|
96
|
+
writeConfig({
|
|
97
|
+
oauth: {
|
|
98
|
+
...oauth,
|
|
99
|
+
tokens: {
|
|
100
|
+
...newTokens,
|
|
101
|
+
expires_at: Date.now() + (newTokens.expires_in ?? 3600) * 1000,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
return newTokens.access_token;
|
|
106
|
+
}
|
|
107
|
+
return oauth.tokens.access_token;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Get MCP base URL for region.
|
|
111
|
+
*/
|
|
112
|
+
export function getMcpBaseUrl(region = "us") {
|
|
113
|
+
return MCP_REGIONS[region] || MCP_REGIONS.us;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Register a dynamic OAuth client with the MCP server.
|
|
117
|
+
*/
|
|
118
|
+
async function registerClient(region) {
|
|
119
|
+
const baseUrl = getMcpBaseUrl(region);
|
|
120
|
+
const res = await fetch(`${baseUrl}/register`, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
headers: { "Content-Type": "application/json" },
|
|
123
|
+
body: JSON.stringify({
|
|
124
|
+
client_name: "amplitude-cli",
|
|
125
|
+
redirect_uris: [`http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`],
|
|
126
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
127
|
+
response_types: ["code"],
|
|
128
|
+
scope: SCOPES,
|
|
129
|
+
token_endpoint_auth_method: "none",
|
|
130
|
+
}),
|
|
131
|
+
});
|
|
132
|
+
if (!res.ok) {
|
|
133
|
+
const body = await res.text();
|
|
134
|
+
throw new Error(`Client registration failed (${res.status}): ${body}`);
|
|
135
|
+
}
|
|
136
|
+
return (await res.json());
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Generate PKCE code_verifier and code_challenge.
|
|
140
|
+
*/
|
|
141
|
+
function generatePKCE() {
|
|
142
|
+
const verifier = randomBytes(32)
|
|
143
|
+
.toString("base64url")
|
|
144
|
+
.replace(/[^a-zA-Z0-9\-._~]/g, "")
|
|
145
|
+
.slice(0, 128);
|
|
146
|
+
const challenge = createHash("sha256").update(verifier).digest("base64url");
|
|
147
|
+
return { verifier, challenge };
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Exchange authorization code for tokens.
|
|
151
|
+
*/
|
|
152
|
+
async function exchangeCode(clientId, code, codeVerifier, region) {
|
|
153
|
+
const baseUrl = getMcpBaseUrl(region);
|
|
154
|
+
const res = await fetch(`${baseUrl}/token`, {
|
|
155
|
+
method: "POST",
|
|
156
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
157
|
+
body: new URLSearchParams({
|
|
158
|
+
grant_type: "authorization_code",
|
|
159
|
+
client_id: clientId,
|
|
160
|
+
code,
|
|
161
|
+
code_verifier: codeVerifier,
|
|
162
|
+
redirect_uri: `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`,
|
|
163
|
+
}),
|
|
164
|
+
});
|
|
165
|
+
if (!res.ok) {
|
|
166
|
+
const body = await res.text();
|
|
167
|
+
throw new Error(`Token exchange failed (${res.status}): ${body}`);
|
|
168
|
+
}
|
|
169
|
+
return (await res.json());
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Refresh an expired access token.
|
|
173
|
+
*/
|
|
174
|
+
async function refreshTokens(clientId, refreshToken, region) {
|
|
175
|
+
const baseUrl = getMcpBaseUrl(region);
|
|
176
|
+
const res = await fetch(`${baseUrl}/token`, {
|
|
177
|
+
method: "POST",
|
|
178
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
179
|
+
body: new URLSearchParams({
|
|
180
|
+
grant_type: "refresh_token",
|
|
181
|
+
client_id: clientId,
|
|
182
|
+
refresh_token: refreshToken,
|
|
183
|
+
}),
|
|
184
|
+
});
|
|
185
|
+
if (!res.ok) {
|
|
186
|
+
const body = await res.text();
|
|
187
|
+
throw new Error(`Token refresh failed (${res.status}): ${body}`);
|
|
188
|
+
}
|
|
189
|
+
return (await res.json());
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Start a local HTTP server to catch the OAuth callback.
|
|
193
|
+
*/
|
|
194
|
+
function waitForCallback() {
|
|
195
|
+
return new Promise((resolve, reject) => {
|
|
196
|
+
const server = createServer((req, res) => {
|
|
197
|
+
const url = new URL(req.url || "/", `http://localhost:${CALLBACK_PORT}`);
|
|
198
|
+
if (url.pathname !== CALLBACK_PATH) {
|
|
199
|
+
res.writeHead(404);
|
|
200
|
+
res.end("Not found");
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const code = url.searchParams.get("code");
|
|
204
|
+
const state = url.searchParams.get("state");
|
|
205
|
+
const error = url.searchParams.get("error");
|
|
206
|
+
if (error) {
|
|
207
|
+
const desc = url.searchParams.get("error_description") || error;
|
|
208
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
209
|
+
res.end(`
|
|
210
|
+
<html><body style="font-family:system-ui;text-align:center;padding:60px">
|
|
211
|
+
<h2>❌ Authentication Failed</h2>
|
|
212
|
+
<p>${desc}</p>
|
|
213
|
+
<p>You can close this tab.</p>
|
|
214
|
+
</body></html>
|
|
215
|
+
`);
|
|
216
|
+
server.close();
|
|
217
|
+
reject(new Error(`OAuth error: ${desc}`));
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (!code || !state) {
|
|
221
|
+
res.writeHead(400);
|
|
222
|
+
res.end("Missing code or state");
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
226
|
+
res.end(`
|
|
227
|
+
<html><body style="font-family:system-ui;text-align:center;padding:60px">
|
|
228
|
+
<h2>✅ Authenticated with Amplitude</h2>
|
|
229
|
+
<p>You can close this tab and return to the terminal.</p>
|
|
230
|
+
</body></html>
|
|
231
|
+
`);
|
|
232
|
+
server.close();
|
|
233
|
+
resolve({ code, state });
|
|
234
|
+
});
|
|
235
|
+
server.listen(CALLBACK_PORT, "127.0.0.1", () => {
|
|
236
|
+
// Server ready
|
|
237
|
+
});
|
|
238
|
+
// Timeout after 5 minutes
|
|
239
|
+
setTimeout(() => {
|
|
240
|
+
server.close();
|
|
241
|
+
reject(new Error("OAuth callback timed out (5 minutes). Try again."));
|
|
242
|
+
}, 5 * 60 * 1000);
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Run the full OAuth login flow.
|
|
247
|
+
* Returns the stored OAuth config.
|
|
248
|
+
*/
|
|
249
|
+
export async function login(region = "us") {
|
|
250
|
+
// 1. Register a client (or reuse existing)
|
|
251
|
+
const existing = getOAuthConfig();
|
|
252
|
+
let clientId;
|
|
253
|
+
if (existing?.client_id && existing?.region === region) {
|
|
254
|
+
clientId = existing.client_id;
|
|
255
|
+
console.error("Using existing OAuth client registration.");
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
console.error("Registering OAuth client with Amplitude...");
|
|
259
|
+
const reg = await registerClient(region);
|
|
260
|
+
clientId = reg.client_id;
|
|
261
|
+
console.error(`Registered client: ${clientId}`);
|
|
262
|
+
}
|
|
263
|
+
// 2. Generate PKCE challenge
|
|
264
|
+
const { verifier, challenge } = generatePKCE();
|
|
265
|
+
const state = randomBytes(16).toString("hex");
|
|
266
|
+
// 3. Build authorization URL
|
|
267
|
+
const baseUrl = getMcpBaseUrl(region);
|
|
268
|
+
const authUrl = new URL(`${baseUrl}/authorize`);
|
|
269
|
+
authUrl.searchParams.set("client_id", clientId);
|
|
270
|
+
authUrl.searchParams.set("redirect_uri", `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`);
|
|
271
|
+
authUrl.searchParams.set("response_type", "code");
|
|
272
|
+
authUrl.searchParams.set("scope", SCOPES);
|
|
273
|
+
authUrl.searchParams.set("state", state);
|
|
274
|
+
authUrl.searchParams.set("code_challenge", challenge);
|
|
275
|
+
authUrl.searchParams.set("code_challenge_method", "S256");
|
|
276
|
+
// 4. Start callback server and open browser
|
|
277
|
+
console.error(`\nOpening browser for Amplitude login...\n`);
|
|
278
|
+
console.error(`If the browser doesn't open, visit:\n${authUrl.toString()}\n`);
|
|
279
|
+
const callbackPromise = waitForCallback();
|
|
280
|
+
// Try to open the browser (best-effort)
|
|
281
|
+
try {
|
|
282
|
+
const { exec } = await import("node:child_process");
|
|
283
|
+
const cmd = process.platform === "darwin"
|
|
284
|
+
? `open "${authUrl.toString()}"`
|
|
285
|
+
: process.platform === "win32"
|
|
286
|
+
? `start "${authUrl.toString()}"`
|
|
287
|
+
: `xdg-open "${authUrl.toString()}" 2>/dev/null || echo "${authUrl.toString()}"`;
|
|
288
|
+
exec(cmd);
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
// Browser open failed — user can copy the URL
|
|
292
|
+
}
|
|
293
|
+
// 5. Wait for callback
|
|
294
|
+
const { code, state: returnedState } = await callbackPromise;
|
|
295
|
+
if (returnedState !== state) {
|
|
296
|
+
throw new Error("OAuth state mismatch — possible CSRF attack. Try again.");
|
|
297
|
+
}
|
|
298
|
+
// 6. Exchange code for tokens
|
|
299
|
+
console.error("Exchanging authorization code for tokens...");
|
|
300
|
+
const tokens = await exchangeCode(clientId, code, verifier, region);
|
|
301
|
+
// 7. Save
|
|
302
|
+
const oauthConfig = {
|
|
303
|
+
client_id: clientId,
|
|
304
|
+
region,
|
|
305
|
+
tokens: {
|
|
306
|
+
...tokens,
|
|
307
|
+
expires_at: Date.now() + (tokens.expires_in ?? 3600) * 1000,
|
|
308
|
+
},
|
|
309
|
+
};
|
|
310
|
+
writeConfig({ oauth: oauthConfig });
|
|
311
|
+
console.error("✓ Logged in and tokens saved to ~/.amplituderc");
|
|
312
|
+
return oauthConfig;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Revoke tokens and clear OAuth config.
|
|
316
|
+
*/
|
|
317
|
+
export async function logout() {
|
|
318
|
+
const oauth = getOAuthConfig();
|
|
319
|
+
if (!oauth?.tokens) {
|
|
320
|
+
console.error("Not logged in.");
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
// Best-effort revoke
|
|
324
|
+
try {
|
|
325
|
+
const baseUrl = getMcpBaseUrl(oauth.region);
|
|
326
|
+
await fetch(`${baseUrl}/revoke`, {
|
|
327
|
+
method: "POST",
|
|
328
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
329
|
+
body: new URLSearchParams({
|
|
330
|
+
client_id: oauth.client_id,
|
|
331
|
+
token: oauth.tokens.refresh_token || oauth.tokens.access_token,
|
|
332
|
+
}),
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
// Revocation is best-effort
|
|
337
|
+
}
|
|
338
|
+
// Clear OAuth from config (keep apiKey/secretKey if present)
|
|
339
|
+
const config = readConfig();
|
|
340
|
+
delete config.oauth;
|
|
341
|
+
writeFileSync(configPath(), JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
342
|
+
console.error("✓ Logged out. OAuth tokens removed.");
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/utils/oauth.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "amplitude-cli",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "CLI for Amplitude analytics via MCP server. OAuth only. Designed for AI agents and humans.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"amp": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "npx tsc",
|
|
11
|
+
"dev": "tsx src/index.ts",
|
|
12
|
+
"start": "node dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"commander": "^13.1.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"typescript": "^5.7.0",
|
|
19
|
+
"tsx": "^4.19.0",
|
|
20
|
+
"@types/node": "^22.0.0"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20"
|
|
28
|
+
},
|
|
29
|
+
"license": "MIT"
|
|
30
|
+
}
|