@caravo/mcp 0.1.3 → 0.1.5

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 (2) hide show
  1. package/dist/index.js +144 -4
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -17,12 +17,33 @@
17
17
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
18
18
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
19
19
  import { z } from "zod";
20
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
21
+ import { homedir } from "os";
22
+ import { join } from "path";
20
23
  import { loadOrCreateWallet } from "./wallet.js";
21
24
  import { fetchWithX402 } from "./x402.js";
22
25
  const API_BASE = process.env.CARAVO_URL ?? "https://caravo.ai";
23
- // Optional API key: if it looks like a real key (am_ prefix), uses balance auth; otherwise x402
24
- const RAW_KEY = process.env.CARAVO_API_KEY;
25
- const API_KEY = RAW_KEY && RAW_KEY.startsWith("am_") ? RAW_KEY : undefined;
26
+ // Config file: ~/.caravo/config.json stores API key set via `login` tool
27
+ const CONFIG_DIR = join(homedir(), ".caravo");
28
+ const CONFIG_FILE = join(CONFIG_DIR, "config.json");
29
+ function loadConfig() {
30
+ try {
31
+ if (!existsSync(CONFIG_FILE))
32
+ return {};
33
+ return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
34
+ }
35
+ catch {
36
+ return {};
37
+ }
38
+ }
39
+ function saveConfig(data) {
40
+ mkdirSync(CONFIG_DIR, { recursive: true });
41
+ writeFileSync(CONFIG_FILE, JSON.stringify(data, null, 2), { mode: 0o600 });
42
+ }
43
+ // Optional API key: env takes priority, then config file; must have am_ prefix
44
+ const RAW_KEY = process.env.CARAVO_API_KEY || loadConfig().api_key;
45
+ // Mutable so the `login` tool can update it mid-session
46
+ let API_KEY = RAW_KEY && RAW_KEY.startsWith("am_") ? RAW_KEY : undefined;
26
47
  const wallet = loadOrCreateWallet();
27
48
  process.stderr.write(`[caravo] wallet: ${wallet.address}\n`);
28
49
  process.stderr.write(API_KEY
@@ -282,6 +303,125 @@ function registerAllTools(server) {
282
303
  ],
283
304
  };
284
305
  });
306
+ // ── Login (browser-based account connect) ────────────────────────────────────
307
+ server.registerTool("login", {
308
+ description: "Connect your Caravo account to enable balance payments and favorites sync. " +
309
+ "Opens caravo.ai in your browser — sign in once and the API key is saved automatically. " +
310
+ "Run this if you started with x402 payments and now want to use your account balance.",
311
+ inputSchema: {},
312
+ }, async () => {
313
+ try {
314
+ // 1. Create one-time session
315
+ const initRes = await fetch(`${API_BASE}/api/auth/mcp-session`, {
316
+ method: "POST",
317
+ headers: { "Content-Type": "application/json" },
318
+ });
319
+ const { token, url } = (await initRes.json());
320
+ // 2. Open browser
321
+ const { exec } = await import("child_process");
322
+ const opener = process.platform === "darwin"
323
+ ? `open "${url}"`
324
+ : process.platform === "win32"
325
+ ? `start "" "${url}"`
326
+ : `xdg-open "${url}"`;
327
+ exec(opener);
328
+ process.stderr.write(`[caravo] login: opened ${url}\n`);
329
+ // 3. Poll every 2s for up to 5 minutes
330
+ const deadline = Date.now() + 5 * 60 * 1000;
331
+ while (Date.now() < deadline) {
332
+ await new Promise((r) => setTimeout(r, 2000));
333
+ const pollRes = await fetch(`${API_BASE}/api/auth/mcp-session?token=${encodeURIComponent(token)}`);
334
+ const poll = (await pollRes.json());
335
+ if (poll.status === "completed" && poll.api_key) {
336
+ // 4. Save to config + activate for this session
337
+ API_KEY = poll.api_key;
338
+ saveConfig({ api_key: poll.api_key });
339
+ process.stderr.write(`[caravo] login: API key saved to ${CONFIG_FILE}\n`);
340
+ return {
341
+ content: [
342
+ {
343
+ type: "text",
344
+ text: [
345
+ `✓ Logged in to Caravo!`,
346
+ ``,
347
+ `API key saved to ${CONFIG_FILE}`,
348
+ `Balance payments are now active for this session.`,
349
+ `Restart the MCP server to also load your favorited tools.`,
350
+ ].join("\n"),
351
+ },
352
+ ],
353
+ };
354
+ }
355
+ if (poll.status === "expired") {
356
+ return {
357
+ content: [{ type: "text", text: "Login expired. Run login again to retry." }],
358
+ isError: true,
359
+ };
360
+ }
361
+ // status === "pending" — keep polling
362
+ }
363
+ return {
364
+ content: [{ type: "text", text: "Login timed out after 5 minutes. Run login again." }],
365
+ isError: true,
366
+ };
367
+ }
368
+ catch (err) {
369
+ return {
370
+ content: [
371
+ {
372
+ type: "text",
373
+ text: `Login failed: ${err instanceof Error ? err.message : String(err)}`,
374
+ },
375
+ ],
376
+ isError: true,
377
+ };
378
+ }
379
+ });
380
+ // ── Logout ──────────────────────────────────────────────────────────────────
381
+ server.registerTool("logout", {
382
+ description: "Disconnect your Caravo account and switch back to x402 wallet payments. " +
383
+ "Removes the saved API key and unregisters all favorited tools from this session.",
384
+ inputSchema: {},
385
+ }, async () => {
386
+ if (!API_KEY) {
387
+ return {
388
+ content: [{ type: "text", text: "Not logged in — already using x402 wallet payments." }],
389
+ };
390
+ }
391
+ // 1. Clear in-memory key
392
+ API_KEY = undefined;
393
+ // 2. Remove key from config file
394
+ try {
395
+ const config = loadConfig();
396
+ delete config.api_key;
397
+ saveConfig(config);
398
+ }
399
+ catch {
400
+ // config file may not exist — that's fine
401
+ }
402
+ // 3. Unregister all favorited tools
403
+ let removedCount = 0;
404
+ for (const [toolId, registered] of registeredFavTools) {
405
+ registered.remove();
406
+ registeredFavTools.delete(toolId);
407
+ removedCount++;
408
+ }
409
+ process.stderr.write(`[caravo] logout: cleared API key, removed ${removedCount} fav tools\n`);
410
+ return {
411
+ content: [
412
+ {
413
+ type: "text",
414
+ text: [
415
+ `✓ Logged out of Caravo.`,
416
+ ``,
417
+ `API key removed from ${CONFIG_FILE}`,
418
+ ...(removedCount > 0 ? [`Unregistered ${removedCount} favorited tool(s).`] : []),
419
+ `Now using x402 wallet payments (${wallet.address}).`,
420
+ ].join("\n"),
421
+ },
422
+ ],
423
+ };
424
+ });
285
425
  // ── List tags ────────────────────────────────────────────────────────────────
286
426
  server.registerTool("list_tags", {
287
427
  description: "List all available tags/categories in the marketplace. Returns tag names, slugs, and tool counts.",
@@ -759,7 +899,7 @@ function registerAllTools(server) {
759
899
  // ─── Main ─────────────────────────────────────────────────────────────────────
760
900
  const server = new McpServer({
761
901
  name: "caravo",
762
- version: "1.0.0",
902
+ version: "0.1.5",
763
903
  }, {
764
904
  instructions: [
765
905
  `You have access to Caravo — a comprehensive platform with a wide variety of ready-to-use tools, APIs, and digital assets at very competitive prices.`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caravo/mcp",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Local stdio MCP server for Caravo with built-in x402 wallet",
5
5
  "type": "module",
6
6
  "bin": {