@caravo/mcp 0.1.2 → 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 (3) hide show
  1. package/README.md +4 -4
  2. package/dist/index.js +105 -6
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -8,7 +8,7 @@ Local stdio MCP server for [Caravo](https://caravo.ai) with built-in x402 wallet
8
8
  # Claude Code
9
9
  claude mcp add caravo -- npx -y @caravo/mcp@latest
10
10
 
11
- # Optional: with API key for balance auth + favorites
11
+ # Optional: with API key for balance auth (favorites work either way)
12
12
  claude mcp add caravo -e CARAVO_API_KEY=am_xxx -- npx -y @caravo/mcp@latest
13
13
  ```
14
14
 
@@ -30,9 +30,9 @@ claude mcp add caravo -e CARAVO_API_KEY=am_xxx -- npx -y @caravo/mcp@latest
30
30
  | `list_tags` | List all categories |
31
31
  | `list_providers` | List all providers |
32
32
  | `get_wallet_info` | Get wallet address and USDC balance |
33
- | `favorite_tool` | Bookmark a tool (requires API key) |
34
- | `unfavorite_tool` | Remove bookmark (requires API key) |
35
- | `list_favorites` | List bookmarked tools (requires API key) |
33
+ | `favorite_tool` | Bookmark a tool (server with API key, local without) |
34
+ | `unfavorite_tool` | Remove bookmark (server with API key, local without) |
35
+ | `list_favorites` | List bookmarked tools (server with API key, local without) |
36
36
  | `list_tool_requests` | Browse tool requests |
37
37
  | `request_tool` | Request a new tool |
38
38
  | `upvote_tool_request` | Upvote a tool request |
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.",
@@ -321,7 +416,9 @@ function registerAllTools(server) {
321
416
  if (!Number.isInteger(per_page) || per_page < 1) {
322
417
  return { content: [{ type: "text", text: "Error: per_page must be a positive integer" }], isError: true };
323
418
  }
324
- per_page = Math.min(100, per_page);
419
+ if (per_page > 100) {
420
+ return { content: [{ type: "text", text: "Error: per_page must be at most 100" }], isError: true };
421
+ }
325
422
  const params = new URLSearchParams();
326
423
  if (query)
327
424
  params.set("query", query);
@@ -548,7 +645,9 @@ function registerAllTools(server) {
548
645
  if (!Number.isInteger(per_page) || per_page < 1) {
549
646
  return { content: [{ type: "text", text: "Error: per_page must be a positive integer" }], isError: true };
550
647
  }
551
- per_page = Math.min(100, per_page);
648
+ if (per_page > 100) {
649
+ return { content: [{ type: "text", text: "Error: per_page must be at most 100" }], isError: true };
650
+ }
552
651
  const params = new URLSearchParams();
553
652
  params.set("status", status);
554
653
  params.set("page", String(page));
@@ -755,7 +854,7 @@ function registerAllTools(server) {
755
854
  // ─── Main ─────────────────────────────────────────────────────────────────────
756
855
  const server = new McpServer({
757
856
  name: "caravo",
758
- version: "1.0.0",
857
+ version: "0.1.4",
759
858
  }, {
760
859
  instructions: [
761
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.2",
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": {