@caravo/mcp 0.1.3 → 0.1.4

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 +99 -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,80 @@ 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
+ });
285
380
  // ── List tags ────────────────────────────────────────────────────────────────
286
381
  server.registerTool("list_tags", {
287
382
  description: "List all available tags/categories in the marketplace. Returns tag names, slugs, and tool counts.",
@@ -759,7 +854,7 @@ function registerAllTools(server) {
759
854
  // ─── Main ─────────────────────────────────────────────────────────────────────
760
855
  const server = new McpServer({
761
856
  name: "caravo",
762
- version: "1.0.0",
857
+ version: "0.1.4",
763
858
  }, {
764
859
  instructions: [
765
860
  `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.4",
4
4
  "description": "Local stdio MCP server for Caravo with built-in x402 wallet",
5
5
  "type": "module",
6
6
  "bin": {