@caravo/mcp 0.1.27 → 0.1.28

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 +85 -79
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -35,6 +35,16 @@ checkForUpdate("@caravo/mcp", VERSION).then((info) => {
35
35
  process.stderr.write(`[caravo] update available: ${info.current} → ${info.latest} (will auto-update on next restart)\n`);
36
36
  }
37
37
  });
38
+ /** Append update notice to the last text content block in a tool response */
39
+ function appendUpdateNotice(result) {
40
+ if (!pendingUpdate)
41
+ return result;
42
+ const lastText = [...result.content].reverse().find((c) => c.type === "text" && c.text);
43
+ if (lastText && lastText.text) {
44
+ lastText.text += `\n\n⚠ Caravo MCP update available: ${pendingUpdate.current} → ${pendingUpdate.latest}. Restart the MCP server to auto-update.`;
45
+ }
46
+ return result;
47
+ }
38
48
  // ─── Shared description blocks (used in both `instructions` and `search_tools`) ─
39
49
  const ABOUT_CARAVO = "Caravo (https://caravo.ai) — the API marketplace for AI agents. 200+ tools at $0.001–$0.05/call.\n" +
40
50
  "Docs & source: https://github.com/Caravo-AI/Caravo-MCP";
@@ -374,7 +384,7 @@ function makeFavToolHandler(tool) {
374
384
  const { dry_run, ...rawInput } = args;
375
385
  const toolInput = resolveLocalFiles(rawInput);
376
386
  if (dry_run) {
377
- return dryRunProbe(tool.id, toolInput);
387
+ return appendUpdateNotice(await dryRunProbe(tool.id, toolInput));
378
388
  }
379
389
  try {
380
390
  const result = await apiPost(`/api/tools/${tool.id}/execute`, toolInput);
@@ -387,26 +397,26 @@ function makeFavToolHandler(tool) {
387
397
  ...formatOutput(result.output),
388
398
  ...reviewLines,
389
399
  ];
390
- return {
400
+ return appendUpdateNotice({
391
401
  content: [{ type: "text", text: lines.join("\n") }],
392
- };
402
+ });
393
403
  }
394
404
  if (result.x402Version || result.accepts) {
395
405
  const price = `$${tool.pricing.price_per_call}`;
396
- return {
406
+ return appendUpdateNotice({
397
407
  content: [{ type: "text", text: buildPaymentRequiredMessage(price) }],
398
408
  isError: true,
399
- };
409
+ });
400
410
  }
401
- return {
411
+ return appendUpdateNotice({
402
412
  content: [
403
413
  { type: "text", text: `Error: ${safeJsonText(result, false)}` },
404
414
  ],
405
415
  isError: true,
406
- };
416
+ });
407
417
  }
408
418
  catch (err) {
409
- return {
419
+ return appendUpdateNotice({
410
420
  content: [
411
421
  {
412
422
  type: "text",
@@ -414,7 +424,7 @@ function makeFavToolHandler(tool) {
414
424
  },
415
425
  ],
416
426
  isError: true,
417
- };
427
+ });
418
428
  }
419
429
  };
420
430
  }
@@ -555,19 +565,15 @@ function registerAllTools(server) {
555
565
  params.set("per_page", String(per_page));
556
566
  params.set("view", "agent");
557
567
  const data = await apiGet(`/api/tools?${params}`);
558
- let text = safeJsonText(data);
559
- if (pendingUpdate) {
560
- text += `\n\n[Update available: @caravo/mcp ${pendingUpdate.current} → ${pendingUpdate.latest}. Will auto-update on next MCP restart.]`;
561
- }
562
- return {
563
- content: [{ type: "text", text }],
564
- };
568
+ return appendUpdateNotice({
569
+ content: [{ type: "text", text: safeJsonText(data) }],
570
+ });
565
571
  }
566
572
  catch (err) {
567
- return {
573
+ return appendUpdateNotice({
568
574
  content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
569
575
  isError: true,
570
- };
576
+ });
571
577
  }
572
578
  });
573
579
  // ── Get tool info ────────────────────────────────────────────────────────────
@@ -586,15 +592,15 @@ function registerAllTools(server) {
586
592
  }
587
593
  try {
588
594
  const data = await apiGet(`/api/tools/${tool_id.trim()}`);
589
- return {
595
+ return appendUpdateNotice({
590
596
  content: [{ type: "text", text: safeJsonText(data) }],
591
- };
597
+ });
592
598
  }
593
599
  catch (err) {
594
- return {
600
+ return appendUpdateNotice({
595
601
  content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
596
602
  isError: true,
597
- };
603
+ });
598
604
  }
599
605
  });
600
606
  // ── use_tool (meta-tool) ─────────────────────────────────────────────────────
@@ -613,15 +619,15 @@ function registerAllTools(server) {
613
619
  }, async ({ tool_id, input, dry_run }) => {
614
620
  const validationError = validateToolId(tool_id);
615
621
  if (validationError) {
616
- return {
622
+ return appendUpdateNotice({
617
623
  content: [{ type: "text", text: `Error: ${validationError}` }],
618
624
  isError: true,
619
- };
625
+ });
620
626
  }
621
627
  const cleanInput = resolveLocalFiles(stripDangerousFields(input));
622
628
  // Dry-run mode: probe cost without executing or paying
623
629
  if (dry_run) {
624
- return dryRunProbe(tool_id.trim(), cleanInput);
630
+ return appendUpdateNotice(await dryRunProbe(tool_id.trim(), cleanInput));
625
631
  }
626
632
  try {
627
633
  const result = await apiPost(`/api/tools/${tool_id.trim()}/execute`, cleanInput);
@@ -634,28 +640,28 @@ function registerAllTools(server) {
634
640
  ...formatOutput(result.output),
635
641
  ...reviewLines,
636
642
  ];
637
- return {
643
+ return appendUpdateNotice({
638
644
  content: [{ type: "text", text: lines.join("\n") }],
639
- };
645
+ });
640
646
  }
641
647
  if (result.x402Version || result.accepts) {
642
648
  const price = result.accepts?.[0]?.amount
643
649
  ? `$${(parseInt(result.accepts[0].amount) / 1e6).toFixed(6)}`
644
650
  : "?";
645
- return {
651
+ return appendUpdateNotice({
646
652
  content: [{ type: "text", text: buildPaymentRequiredMessage(price) }],
647
653
  isError: true,
648
- };
654
+ });
649
655
  }
650
- return {
656
+ return appendUpdateNotice({
651
657
  content: [
652
658
  { type: "text", text: `Error: ${safeJsonText(result, false)}` },
653
659
  ],
654
660
  isError: true,
655
- };
661
+ });
656
662
  }
657
663
  catch (err) {
658
- return {
664
+ return appendUpdateNotice({
659
665
  content: [
660
666
  {
661
667
  type: "text",
@@ -663,7 +669,7 @@ function registerAllTools(server) {
663
669
  },
664
670
  ],
665
671
  isError: true,
666
- };
672
+ });
667
673
  }
668
674
  });
669
675
  // ── Submit review / upvote ───────────────────────────────────────────────────
@@ -717,12 +723,12 @@ function registerAllTools(server) {
717
723
  lines.push(`This was a 5/5 review — consider saving tool_id="${upvotedToolId}" to your memory for future reuse.`);
718
724
  }
719
725
  }
720
- return { content: [{ type: "text", text: lines.join("\n") }] };
726
+ return appendUpdateNotice({ content: [{ type: "text", text: lines.join("\n") }] });
721
727
  }
722
- return {
728
+ return appendUpdateNotice({
723
729
  content: [{ type: "text", text: result.error ? `Error: ${result.error}` : safeJsonText(result) }],
724
730
  isError: true,
725
- };
731
+ });
726
732
  }
727
733
  // New review mode
728
734
  if (rating == null || !comment) {
@@ -749,10 +755,10 @@ function registerAllTools(server) {
749
755
  agent_id,
750
756
  });
751
757
  if (result.error) {
752
- return {
758
+ return appendUpdateNotice({
753
759
  content: [{ type: "text", text: `Error: ${result.error}` }],
754
760
  isError: true,
755
- };
761
+ });
756
762
  }
757
763
  // The API returns the review record with tool_id derived from execution
758
764
  const reviewToolId = result.tool_id || "unknown";
@@ -767,13 +773,13 @@ function registerAllTools(server) {
767
773
  lines.push(`This tool scored 5/5 — consider saving tool_id="${reviewToolId}" to your memory for future reuse.`);
768
774
  }
769
775
  }
770
- return { content: [{ type: "text", text: lines.join("\n") }] };
776
+ return appendUpdateNotice({ content: [{ type: "text", text: lines.join("\n") }] });
771
777
  }
772
778
  catch (err) {
773
- return {
779
+ return appendUpdateNotice({
774
780
  content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
775
781
  isError: true,
776
- };
782
+ });
777
783
  }
778
784
  });
779
785
  // ── Wallet info ──────────────────────────────────────────────────────────────
@@ -835,14 +841,14 @@ function registerAllTools(server) {
835
841
  else {
836
842
  info.note = "Send USDC on Base to this address to enable automatic x402 payments.";
837
843
  }
838
- return {
844
+ return appendUpdateNotice({
839
845
  content: [
840
846
  {
841
847
  type: "text",
842
848
  text: JSON.stringify(info, null, 2),
843
849
  },
844
850
  ],
845
- };
851
+ });
846
852
  });
847
853
  // ── Login (browser-based account connect) ────────────────────────────────────
848
854
  server.registerTool("login", {
@@ -974,15 +980,15 @@ function registerAllTools(server) {
974
980
  }, async () => {
975
981
  try {
976
982
  const data = await apiGet("/api/tags");
977
- return {
983
+ return appendUpdateNotice({
978
984
  content: [{ type: "text", text: safeJsonText(data) }],
979
- };
985
+ });
980
986
  }
981
987
  catch (err) {
982
- return {
988
+ return appendUpdateNotice({
983
989
  content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
984
990
  isError: true,
985
- };
991
+ });
986
992
  }
987
993
  });
988
994
  // ── List providers ───────────────────────────────────────────────────────────
@@ -992,15 +998,15 @@ function registerAllTools(server) {
992
998
  }, async () => {
993
999
  try {
994
1000
  const data = await apiGet("/api/providers");
995
- return {
1001
+ return appendUpdateNotice({
996
1002
  content: [{ type: "text", text: safeJsonText(data) }],
997
- };
1003
+ });
998
1004
  }
999
1005
  catch (err) {
1000
- return {
1006
+ return appendUpdateNotice({
1001
1007
  content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
1002
1008
  isError: true,
1003
- };
1009
+ });
1004
1010
  }
1005
1011
  });
1006
1012
  // ── Tool Requests ───────────────────────────────────────────────────────────
@@ -1027,15 +1033,15 @@ function registerAllTools(server) {
1027
1033
  params.set("page", String(page));
1028
1034
  params.set("per_page", String(per_page));
1029
1035
  const data = await apiGet(`/api/tool-requests?${params}`);
1030
- return {
1036
+ return appendUpdateNotice({
1031
1037
  content: [{ type: "text", text: safeJsonText(data) }],
1032
- };
1038
+ });
1033
1039
  }
1034
1040
  catch (err) {
1035
- return {
1041
+ return appendUpdateNotice({
1036
1042
  content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
1037
1043
  isError: true,
1038
- };
1044
+ });
1039
1045
  }
1040
1046
  });
1041
1047
  server.registerTool("request_tool", {
@@ -1059,12 +1065,12 @@ function registerAllTools(server) {
1059
1065
  agent_id,
1060
1066
  });
1061
1067
  if (result.error) {
1062
- return {
1068
+ return appendUpdateNotice({
1063
1069
  content: [{ type: "text", text: `Error: ${result.error}` }],
1064
1070
  isError: true,
1065
- };
1071
+ });
1066
1072
  }
1067
- return {
1073
+ return appendUpdateNotice({
1068
1074
  content: [
1069
1075
  {
1070
1076
  type: "text",
@@ -1077,13 +1083,13 @@ function registerAllTools(server) {
1077
1083
  ].join("\n"),
1078
1084
  },
1079
1085
  ],
1080
- };
1086
+ });
1081
1087
  }
1082
1088
  catch (err) {
1083
- return {
1089
+ return appendUpdateNotice({
1084
1090
  content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
1085
1091
  isError: true,
1086
- };
1092
+ });
1087
1093
  }
1088
1094
  });
1089
1095
  server.registerTool("upvote_tool_request", {
@@ -1099,21 +1105,21 @@ function registerAllTools(server) {
1099
1105
  execution_id,
1100
1106
  });
1101
1107
  if (result.error) {
1102
- return {
1108
+ return appendUpdateNotice({
1103
1109
  content: [{ type: "text", text: `Error: ${result.error}` }],
1104
1110
  isError: true,
1105
- };
1111
+ });
1106
1112
  }
1107
1113
  const action = result.action === "already_upvoted" ? "Already upvoted" : "Upvoted";
1108
- return {
1114
+ return appendUpdateNotice({
1109
1115
  content: [{ type: "text", text: `✓ ${action} tool request ${request_id}` }],
1110
- };
1116
+ });
1111
1117
  }
1112
1118
  catch (err) {
1113
- return {
1119
+ return appendUpdateNotice({
1114
1120
  content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
1115
1121
  isError: true,
1116
- };
1122
+ });
1117
1123
  }
1118
1124
  });
1119
1125
  // ── Favorites management ─────────────────────────────────────────────────────
@@ -1141,7 +1147,7 @@ function registerAllTools(server) {
1141
1147
  };
1142
1148
  }
1143
1149
  const tools = result.data ?? [];
1144
- return {
1150
+ return appendUpdateNotice({
1145
1151
  content: [
1146
1152
  {
1147
1153
  type: "text",
@@ -1157,13 +1163,13 @@ function registerAllTools(server) {
1157
1163
  }),
1158
1164
  },
1159
1165
  ],
1160
- };
1166
+ });
1161
1167
  }
1162
1168
  catch (err) {
1163
- return {
1169
+ return appendUpdateNotice({
1164
1170
  content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
1165
1171
  isError: true,
1166
- };
1172
+ });
1167
1173
  }
1168
1174
  });
1169
1175
  server.registerTool("favorite_tool", {
@@ -1200,7 +1206,7 @@ function registerAllTools(server) {
1200
1206
  if (tool) {
1201
1207
  registerFavTool(server, tool);
1202
1208
  }
1203
- return {
1209
+ return appendUpdateNotice({
1204
1210
  content: [
1205
1211
  {
1206
1212
  type: "text",
@@ -1212,13 +1218,13 @@ function registerAllTools(server) {
1212
1218
  ].join("\n"),
1213
1219
  },
1214
1220
  ],
1215
- };
1221
+ });
1216
1222
  }
1217
1223
  catch (err) {
1218
- return {
1224
+ return appendUpdateNotice({
1219
1225
  content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
1220
1226
  isError: true,
1221
- };
1227
+ });
1222
1228
  }
1223
1229
  });
1224
1230
  server.registerTool("unfavorite_tool", {
@@ -1253,7 +1259,7 @@ function registerAllTools(server) {
1253
1259
  registered.remove();
1254
1260
  registeredFavTools.delete(tool_id);
1255
1261
  }
1256
- return {
1262
+ return appendUpdateNotice({
1257
1263
  content: [
1258
1264
  {
1259
1265
  type: "text",
@@ -1262,13 +1268,13 @@ function registerAllTools(server) {
1262
1268
  : `"${tool_id}" was not in your favorites.`,
1263
1269
  },
1264
1270
  ],
1265
- };
1271
+ });
1266
1272
  }
1267
1273
  catch (err) {
1268
- return {
1274
+ return appendUpdateNotice({
1269
1275
  content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
1270
1276
  isError: true,
1271
- };
1277
+ });
1272
1278
  }
1273
1279
  });
1274
1280
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caravo/mcp",
3
- "version": "0.1.27",
3
+ "version": "0.1.28",
4
4
  "description": "The API marketplace built for autonomous AI agents. Search, execute, and pay for 200+ tools at $0.001–0.05 per call.",
5
5
  "type": "module",
6
6
  "bin": {