@xlmtools/cli 0.1.1 → 0.2.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.
Files changed (86) hide show
  1. package/README.md +18 -12
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +6 -1
  4. package/dist/lib/api-fetch.d.ts +19 -0
  5. package/dist/lib/api-fetch.js +20 -0
  6. package/dist/lib/budget.d.ts +14 -0
  7. package/dist/lib/cache.d.ts +7 -0
  8. package/dist/lib/config.d.ts +2 -0
  9. package/dist/lib/format.d.ts +15 -0
  10. package/dist/lib/logger.d.ts +2 -0
  11. package/dist/lib/wallet.d.ts +9 -0
  12. package/dist/server.d.ts +22 -0
  13. package/dist/server.js +89 -0
  14. package/dist/tools/budget.d.ts +2 -0
  15. package/dist/tools/crypto.d.ts +2 -0
  16. package/dist/tools/crypto.js +2 -1
  17. package/dist/tools/dex-candles.d.ts +2 -0
  18. package/dist/tools/dex-candles.js +2 -1
  19. package/dist/tools/dex-orderbook.d.ts +2 -0
  20. package/dist/tools/dex-orderbook.js +2 -1
  21. package/dist/tools/dex-trades.d.ts +2 -0
  22. package/dist/tools/dex-trades.js +2 -1
  23. package/dist/tools/domain.d.ts +2 -0
  24. package/dist/tools/domain.js +2 -1
  25. package/dist/tools/image.d.ts +2 -0
  26. package/dist/tools/image.js +2 -1
  27. package/dist/tools/oracle-price.d.ts +2 -0
  28. package/dist/tools/oracle-price.js +2 -1
  29. package/dist/tools/research.d.ts +2 -0
  30. package/dist/tools/research.js +2 -1
  31. package/dist/tools/scrape.d.ts +2 -0
  32. package/dist/tools/scrape.js +2 -1
  33. package/dist/tools/screenshot.d.ts +2 -0
  34. package/dist/tools/screenshot.js +2 -1
  35. package/dist/tools/search.d.ts +2 -0
  36. package/dist/tools/search.js +2 -1
  37. package/dist/tools/stellar-account.d.ts +2 -0
  38. package/dist/tools/stellar-account.js +2 -1
  39. package/dist/tools/stellar-asset.d.ts +2 -0
  40. package/dist/tools/stellar-asset.js +2 -1
  41. package/dist/tools/stellar-pools.d.ts +2 -0
  42. package/dist/tools/stellar-pools.js +2 -1
  43. package/dist/tools/stocks.d.ts +2 -0
  44. package/dist/tools/stocks.js +2 -1
  45. package/dist/tools/swap-quote.d.ts +2 -0
  46. package/dist/tools/swap-quote.js +2 -1
  47. package/dist/tools/tools-list.d.ts +2 -0
  48. package/dist/tools/wallet-tool.d.ts +2 -0
  49. package/dist/tools/weather.d.ts +2 -0
  50. package/dist/tools/weather.js +2 -1
  51. package/dist/tools/youtube.d.ts +2 -0
  52. package/dist/tools/youtube.js +2 -1
  53. package/package.json +27 -3
  54. package/dist/index.js +0 -77
  55. package/dist/tools/card.js +0 -51
  56. package/dist/tools/reddit.js +0 -40
  57. package/src/cli.ts +0 -240
  58. package/src/index.ts +0 -90
  59. package/src/lib/budget.ts +0 -78
  60. package/src/lib/cache.ts +0 -66
  61. package/src/lib/config.ts +0 -18
  62. package/src/lib/format.ts +0 -51
  63. package/src/lib/logger.ts +0 -6
  64. package/src/lib/wallet.ts +0 -143
  65. package/src/tools/budget.ts +0 -67
  66. package/src/tools/crypto.ts +0 -25
  67. package/src/tools/dex-candles.ts +0 -52
  68. package/src/tools/dex-orderbook.ts +0 -45
  69. package/src/tools/dex-trades.ts +0 -51
  70. package/src/tools/domain.ts +0 -24
  71. package/src/tools/image.ts +0 -49
  72. package/src/tools/oracle-price.ts +0 -42
  73. package/src/tools/research.ts +0 -47
  74. package/src/tools/scrape.ts +0 -41
  75. package/src/tools/screenshot.ts +0 -46
  76. package/src/tools/search.ts +0 -47
  77. package/src/tools/stellar-account.ts +0 -38
  78. package/src/tools/stellar-asset.ts +0 -39
  79. package/src/tools/stellar-pools.ts +0 -45
  80. package/src/tools/stocks.ts +0 -43
  81. package/src/tools/swap-quote.ts +0 -43
  82. package/src/tools/tools-list.ts +0 -22
  83. package/src/tools/wallet-tool.ts +0 -51
  84. package/src/tools/weather.ts +0 -24
  85. package/src/tools/youtube.ts +0 -49
  86. package/tsconfig.json +0 -13
package/README.md CHANGED
@@ -1,30 +1,36 @@
1
1
  # @xlmtools/cli
2
2
 
3
- XLMTools CLI — the MCP server that runs locally on the user's machine. Handles tool registration, payment signing, budget tracking, and response caching.
3
+ XLMTools CLI — the universal standalone CLI that runs on the user's machine. Provides the `xlm` binary for direct terminal use and exports the `createMcpServer()` factory that powers the `@xlmtools/mcp` stdio server. Handles tool registration, payment signing, budget tracking, and response caching.
4
4
 
5
5
  ## How it works
6
6
 
7
- This package is an MCP stdio server. It's started automatically by Claude, Cursor, or any MCP-compatible host when a user calls a XLMTools tool.
7
+ This package ships two things:
8
+
9
+ 1. A standalone `xlm` binary — the universal path. Any agent host with a Bash tool can invoke XLMTools by shelling out to `xlm <tool> <args>`.
10
+ 2. A `createMcpServer()` factory exported from `main`/`types` — consumed by the sibling `@xlmtools/mcp` package, which wraps it in a thin stdio adapter for MCP-capable hosts.
8
11
 
9
12
  ```
10
- MCP Host (Claude, Cursor, Windsurf)
11
- | stdio
12
- v
13
- @xlmtools/cli (this package)
14
- | - 21 tools registered via @modelcontextprotocol/sdk
15
- | - mppx polyfills fetch to auto-handle 402 payments
16
- | - budget enforcement (withBudget)
17
- | - response caching (withCache, 5-min TTL)
13
+ Agent host
18
14
  |
19
- | HTTPS
15
+ |-- Bash tool --> xlm (this package's bin)
16
+ |
17
+ |-- MCP stdio --> @xlmtools/mcp ──> imports createMcpServer() from @xlmtools/cli
20
18
  v
21
19
  @xlmtools/api (hosted API server)
20
+ - 21 tools registered via @modelcontextprotocol/sdk
21
+ - mppx polyfills fetch to auto-handle 402 payments
22
+ - budget enforcement (withBudget)
23
+ - response caching (withCache, 5-min TTL)
22
24
  ```
23
25
 
24
26
  ## Install (for users)
25
27
 
26
28
  ```bash
27
- claude mcp add xlmtools npx @xlmtools/cli
29
+ # Standalone CLI (universal works with any agent host that has Bash)
30
+ npm install -g @xlmtools/cli
31
+
32
+ # MCP server (optional fast-path — install the sibling package)
33
+ claude mcp add xlmtools npx @xlmtools/mcp
28
34
  ```
29
35
 
30
36
  On first run, the CLI:
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js CHANGED
@@ -3,6 +3,7 @@ import { Mppx } from "mppx/client";
3
3
  import { stellar } from "@stellar/mpp/charge/client";
4
4
  import { Horizon } from "@stellar/stellar-sdk";
5
5
  import { loadOrCreateWallet, getKeypair } from "./lib/wallet.js";
6
+ import { apiFetch } from "./lib/api-fetch.js";
6
7
  import { TOOL_PRICES } from "./lib/config.js";
7
8
  import { logger } from "./lib/logger.js";
8
9
  // ── Arg parsing ──────────────────────────────────────────
@@ -190,7 +191,11 @@ async function main() {
190
191
  if (isPaid) {
191
192
  process.stderr.write(` Tool: ${tool} · Cost: $${TOOL_PRICES[tool]} USDC\n`);
192
193
  }
193
- const res = await fetch(url, init);
194
+ // Route through apiFetch so the X-XLMTools-Client header (and any
195
+ // future cross-cutting concerns like retries / user-agent) are
196
+ // applied consistently with the MCP tools. apiFetch detects the
197
+ // full-URL form and passes it straight through.
198
+ const res = await apiFetch(config, url, init);
194
199
  if (!res.ok) {
195
200
  const text = await res.text();
196
201
  process.stderr.write(`Error ${res.status}: ${text}\n`);
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Shared fetch helper for tool calls against the XLMTools API.
3
+ *
4
+ * Every API request gets stamped with `X-XLMTools-Client: <G-address>`
5
+ * so the server can attribute calls back to the user's wallet on the
6
+ * /stats/by-client endpoint. The header is self-declared (no signature)
7
+ * which is fine because:
8
+ * - Paid calls are additionally verified by the Stellar tx receipt
9
+ * - Free calls have no economic value to spoof
10
+ *
11
+ * Usage:
12
+ * const config = loadOrCreateWallet();
13
+ * const res = await apiFetch(config, `/crypto?ids=${ids}`);
14
+ */
15
+ export interface ClientConfig {
16
+ apiUrl: string;
17
+ stellarPublicKey: string;
18
+ }
19
+ export declare function apiFetch(config: ClientConfig, path: string, init?: RequestInit): Promise<Response>;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Shared fetch helper for tool calls against the XLMTools API.
3
+ *
4
+ * Every API request gets stamped with `X-XLMTools-Client: <G-address>`
5
+ * so the server can attribute calls back to the user's wallet on the
6
+ * /stats/by-client endpoint. The header is self-declared (no signature)
7
+ * which is fine because:
8
+ * - Paid calls are additionally verified by the Stellar tx receipt
9
+ * - Free calls have no economic value to spoof
10
+ *
11
+ * Usage:
12
+ * const config = loadOrCreateWallet();
13
+ * const res = await apiFetch(config, `/crypto?ids=${ids}`);
14
+ */
15
+ export async function apiFetch(config, path, init) {
16
+ const url = path.startsWith("http") ? path : `${config.apiUrl}${path}`;
17
+ const headers = new Headers(init?.headers);
18
+ headers.set("X-XLMTools-Client", config.stellarPublicKey);
19
+ return fetch(url, { ...init, headers });
20
+ }
@@ -0,0 +1,14 @@
1
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
+ export declare function setBudget(max: number): void;
3
+ export declare function clearBudget(): void;
4
+ export declare function getStatus(): {
5
+ max: number | null;
6
+ spent: number;
7
+ remaining: number | null;
8
+ };
9
+ /**
10
+ * Wrap a paid tool call with budget checking.
11
+ * If budget would be exceeded, returns an error without calling the API.
12
+ * On success, records the spend.
13
+ */
14
+ export declare function withBudget(toolName: string, fn: () => Promise<CallToolResult>): Promise<CallToolResult>;
@@ -0,0 +1,7 @@
1
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
+ /**
3
+ * Wrap a tool call with response caching.
4
+ * Identical tool+params within the TTL return the cached result
5
+ * with no API call and no payment.
6
+ */
7
+ export declare function withCache(toolName: string, params: Record<string, unknown>, fn: () => Promise<CallToolResult>): Promise<CallToolResult>;
@@ -0,0 +1,2 @@
1
+ export declare const TOOL_PRICES: Record<string, string>;
2
+ export declare const FREE_TOOLS: Set<string>;
@@ -0,0 +1,15 @@
1
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
+ export interface ReceiptInfo {
3
+ tx_hash: string;
4
+ amount: string;
5
+ currency: string;
6
+ network: string;
7
+ }
8
+ export declare function ok(data: unknown): CallToolResult;
9
+ /**
10
+ * Format a paid tool response, appending a receipt line if present.
11
+ * Strips the receipt from the data to avoid cluttering the JSON output,
12
+ * then appends a human-readable payment line.
13
+ */
14
+ export declare function okPaid(data: Record<string, unknown>): CallToolResult;
15
+ export declare function err(message: string): CallToolResult;
@@ -0,0 +1,2 @@
1
+ import pino from "pino";
2
+ export declare const logger: pino.Logger<never, boolean>;
@@ -0,0 +1,9 @@
1
+ import { Keypair } from "@stellar/stellar-sdk";
2
+ interface XLMToolsConfig {
3
+ stellarPrivateKey: string;
4
+ stellarPublicKey: string;
5
+ apiUrl: string;
6
+ }
7
+ export declare function loadOrCreateWallet(): XLMToolsConfig;
8
+ export declare function getKeypair(config: XLMToolsConfig): Keypair;
9
+ export {};
@@ -0,0 +1,22 @@
1
+ /**
2
+ * XLMTools MCP server factory.
3
+ *
4
+ * Builds and returns a fully-registered `McpServer` instance —
5
+ * without connecting any transport. Consumers are responsible for
6
+ * choosing the transport and calling `server.connect(transport)`.
7
+ *
8
+ * Currently used by `@xlmtools/mcp` (stdio transport wrapper).
9
+ * Could also be used to host over HTTP/SSE in the future by wiring
10
+ * a different transport.
11
+ */
12
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
13
+ /**
14
+ * Build a fully-configured XLMTools MCP server with all 21 tools
15
+ * registered. The caller must connect a transport.
16
+ *
17
+ * Side effects on first call:
18
+ * - Loads or creates the user's Stellar wallet at ~/.xlmtools/config.json
19
+ * - Initializes Mppx with a Stellar charge method (polyfills fetch
20
+ * to auto-handle 402 payment challenges)
21
+ */
22
+ export declare function createMcpServer(): McpServer;
package/dist/server.js ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * XLMTools MCP server factory.
3
+ *
4
+ * Builds and returns a fully-registered `McpServer` instance —
5
+ * without connecting any transport. Consumers are responsible for
6
+ * choosing the transport and calling `server.connect(transport)`.
7
+ *
8
+ * Currently used by `@xlmtools/mcp` (stdio transport wrapper).
9
+ * Could also be used to host over HTTP/SSE in the future by wiring
10
+ * a different transport.
11
+ */
12
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
13
+ import { Mppx } from "mppx/client";
14
+ import { stellar } from "@stellar/mpp/charge/client";
15
+ import { loadOrCreateWallet, getKeypair } from "./lib/wallet.js";
16
+ import { logger } from "./lib/logger.js";
17
+ import { registerCryptoTool } from "./tools/crypto.js";
18
+ import { registerWeatherTool } from "./tools/weather.js";
19
+ import { registerDomainTool } from "./tools/domain.js";
20
+ import { registerToolsListTool } from "./tools/tools-list.js";
21
+ import { registerWalletTool } from "./tools/wallet-tool.js";
22
+ import { registerSearchTool } from "./tools/search.js";
23
+ import { registerResearchTool } from "./tools/research.js";
24
+ import { registerYoutubeTool } from "./tools/youtube.js";
25
+ import { registerScreenshotTool } from "./tools/screenshot.js";
26
+ import { registerScrapeTool } from "./tools/scrape.js";
27
+ import { registerImageTool } from "./tools/image.js";
28
+ import { registerStocksTool } from "./tools/stocks.js";
29
+ import { registerDexOrderbookTool } from "./tools/dex-orderbook.js";
30
+ import { registerDexCandlesTool } from "./tools/dex-candles.js";
31
+ import { registerDexTradesTool } from "./tools/dex-trades.js";
32
+ import { registerSwapQuoteTool } from "./tools/swap-quote.js";
33
+ import { registerStellarAssetTool } from "./tools/stellar-asset.js";
34
+ import { registerStellarAccountTool } from "./tools/stellar-account.js";
35
+ import { registerStellarPoolsTool } from "./tools/stellar-pools.js";
36
+ import { registerOraclePriceTool } from "./tools/oracle-price.js";
37
+ import { registerBudgetTool } from "./tools/budget.js";
38
+ /**
39
+ * Build a fully-configured XLMTools MCP server with all 21 tools
40
+ * registered. The caller must connect a transport.
41
+ *
42
+ * Side effects on first call:
43
+ * - Loads or creates the user's Stellar wallet at ~/.xlmtools/config.json
44
+ * - Initializes Mppx with a Stellar charge method (polyfills fetch
45
+ * to auto-handle 402 payment challenges)
46
+ */
47
+ export function createMcpServer() {
48
+ const config = loadOrCreateWallet();
49
+ const keypair = getKeypair(config);
50
+ // Mppx polyfills global fetch to auto-handle 402 payments
51
+ Mppx.create({
52
+ methods: [
53
+ stellar.charge({
54
+ keypair,
55
+ mode: "pull",
56
+ onProgress(event) {
57
+ logger.debug({ eventType: event.type }, "MPP payment event");
58
+ },
59
+ }),
60
+ ],
61
+ });
62
+ // { logging: {} } enables ctx.mcpReq.log() in tool handlers
63
+ const server = new McpServer({ name: "xlmtools", version: "0.2.0" }, { capabilities: { tools: {}, logging: {} } });
64
+ // Free tools
65
+ registerCryptoTool(server);
66
+ registerWeatherTool(server);
67
+ registerDomainTool(server);
68
+ registerToolsListTool(server);
69
+ registerWalletTool(server);
70
+ registerBudgetTool(server);
71
+ // Paid tools
72
+ registerSearchTool(server);
73
+ registerResearchTool(server);
74
+ registerYoutubeTool(server);
75
+ registerScreenshotTool(server);
76
+ registerScrapeTool(server);
77
+ registerImageTool(server);
78
+ registerStocksTool(server);
79
+ // Stellar-native tools (free)
80
+ registerDexOrderbookTool(server);
81
+ registerDexCandlesTool(server);
82
+ registerDexTradesTool(server);
83
+ registerSwapQuoteTool(server);
84
+ registerStellarAssetTool(server);
85
+ registerStellarAccountTool(server);
86
+ registerStellarPoolsTool(server);
87
+ registerOraclePriceTool(server);
88
+ return server;
89
+ }
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerBudgetTool(server: McpServer): void;
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerCryptoTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { ok, err } from "../lib/format.js";
4
5
  export function registerCryptoTool(server) {
5
6
  server.registerTool("crypto", {
@@ -11,7 +12,7 @@ export function registerCryptoTool(server) {
11
12
  }, async ({ ids, vs_currency }) => {
12
13
  try {
13
14
  const config = loadOrCreateWallet();
14
- const res = await fetch(`${config.apiUrl}/crypto?ids=${encodeURIComponent(ids)}&vs_currency=${vs_currency}`);
15
+ const res = await apiFetch(config, `/crypto?ids=${encodeURIComponent(ids)}&vs_currency=${vs_currency}`);
15
16
  if (!res.ok)
16
17
  return err(`Crypto API error: ${res.status}`);
17
18
  return ok(await res.json());
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerDexCandlesTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { ok, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  export function registerDexCandlesTool(server) {
@@ -31,7 +32,7 @@ export function registerDexCandlesTool(server) {
31
32
  resolution,
32
33
  limit: String(limit),
33
34
  });
34
- const res = await fetch(`${config.apiUrl}/dex-candles?${params}`);
35
+ const res = await apiFetch(config, `/dex-candles?${params}`);
35
36
  if (!res.ok) {
36
37
  const body = await res.text();
37
38
  return err(`Candles error ${res.status}: ${body}`);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerDexOrderbookTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { ok, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  export function registerDexOrderbookTool(server) {
@@ -22,7 +23,7 @@ export function registerDexOrderbookTool(server) {
22
23
  logger.debug({ pair, limit }, "dex-orderbook invoked");
23
24
  try {
24
25
  const config = loadOrCreateWallet();
25
- const res = await fetch(`${config.apiUrl}/dex-orderbook?pair=${encodeURIComponent(pair)}&limit=${limit}`);
26
+ const res = await apiFetch(config, `/dex-orderbook?pair=${encodeURIComponent(pair)}&limit=${limit}`);
26
27
  if (!res.ok) {
27
28
  const body = await res.text();
28
29
  return err(`Orderbook error ${res.status}: ${body}`);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerDexTradesTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { ok, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  export function registerDexTradesTool(server) {
@@ -30,7 +31,7 @@ export function registerDexTradesTool(server) {
30
31
  limit: String(limit),
31
32
  trade_type,
32
33
  });
33
- const res = await fetch(`${config.apiUrl}/dex-trades?${params}`);
34
+ const res = await apiFetch(config, `/dex-trades?${params}`);
34
35
  if (!res.ok) {
35
36
  const body = await res.text();
36
37
  return err(`Trades error ${res.status}: ${body}`);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerDomainTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { ok, err } from "../lib/format.js";
4
5
  export function registerDomainTool(server) {
5
6
  server.registerTool("domain", {
@@ -10,7 +11,7 @@ export function registerDomainTool(server) {
10
11
  }, async ({ name }) => {
11
12
  try {
12
13
  const config = loadOrCreateWallet();
13
- const res = await fetch(`${config.apiUrl}/domain?name=${encodeURIComponent(name)}`);
14
+ const res = await apiFetch(config, `/domain?name=${encodeURIComponent(name)}`);
14
15
  if (!res.ok)
15
16
  return err(`Domain API error: ${res.status}`);
16
17
  return ok(await res.json());
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerImageTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { okPaid, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  import { TOOL_PRICES } from "../lib/config.js";
@@ -22,7 +23,7 @@ export function registerImageTool(server) {
22
23
  return withCache("image", { prompt, size }, () => withBudget("image", async () => {
23
24
  try {
24
25
  const config = loadOrCreateWallet();
25
- const res = await fetch(`${config.apiUrl}/image`, {
26
+ const res = await apiFetch(config, `/image`, {
26
27
  method: "POST",
27
28
  headers: { "Content-Type": "application/json" },
28
29
  body: JSON.stringify({ prompt, size }),
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerOraclePriceTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { ok, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  export function registerOraclePriceTool(server) {
@@ -21,7 +22,7 @@ export function registerOraclePriceTool(server) {
21
22
  try {
22
23
  const config = loadOrCreateWallet();
23
24
  const params = new URLSearchParams({ asset, feed });
24
- const res = await fetch(`${config.apiUrl}/oracle-price?${params}`);
25
+ const res = await apiFetch(config, `/oracle-price?${params}`);
25
26
  if (!res.ok) {
26
27
  const body = await res.text();
27
28
  return err(`Oracle error ${res.status}: ${body}`);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerResearchTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { okPaid, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  import { TOOL_PRICES } from "../lib/config.js";
@@ -22,7 +23,7 @@ export function registerResearchTool(server) {
22
23
  return withCache("research", { query, num_results }, () => withBudget("research", async () => {
23
24
  try {
24
25
  const config = loadOrCreateWallet();
25
- const res = await fetch(`${config.apiUrl}/research?q=${encodeURIComponent(query)}&num_results=${num_results}`);
26
+ const res = await apiFetch(config, `/research?q=${encodeURIComponent(query)}&num_results=${num_results}`);
26
27
  if (!res.ok) {
27
28
  const body = await res.text();
28
29
  return err(`Research API error ${res.status}: ${body}`);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerScrapeTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { okPaid, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  import { TOOL_PRICES } from "../lib/config.js";
@@ -16,7 +17,7 @@ export function registerScrapeTool(server) {
16
17
  return withCache("scrape", { url }, () => withBudget("scrape", async () => {
17
18
  try {
18
19
  const config = loadOrCreateWallet();
19
- const res = await fetch(`${config.apiUrl}/scrape?url=${encodeURIComponent(url)}`);
20
+ const res = await apiFetch(config, `/scrape?url=${encodeURIComponent(url)}`);
20
21
  if (!res.ok) {
21
22
  const body = await res.text();
22
23
  return err(`Scrape API error ${res.status}: ${body}`);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerScreenshotTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { okPaid, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  import { TOOL_PRICES } from "../lib/config.js";
@@ -21,7 +22,7 @@ export function registerScreenshotTool(server) {
21
22
  try {
22
23
  const config = loadOrCreateWallet();
23
24
  const params = new URLSearchParams({ url, format });
24
- const res = await fetch(`${config.apiUrl}/screenshot?${params.toString()}`);
25
+ const res = await apiFetch(config, `/screenshot?${params.toString()}`);
25
26
  if (!res.ok) {
26
27
  const body = await res.text();
27
28
  return err(`Screenshot API error ${res.status}: ${body}`);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerSearchTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { okPaid, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  import { TOOL_PRICES } from "../lib/config.js";
@@ -22,7 +23,7 @@ export function registerSearchTool(server) {
22
23
  return withCache("search", { query, count }, () => withBudget("search", async () => {
23
24
  try {
24
25
  const config = loadOrCreateWallet();
25
- const res = await fetch(`${config.apiUrl}/search?q=${encodeURIComponent(query)}&count=${count}`);
26
+ const res = await apiFetch(config, `/search?q=${encodeURIComponent(query)}&count=${count}`);
26
27
  if (!res.ok) {
27
28
  const body = await res.text();
28
29
  return err(`Search API error ${res.status}: ${body}`);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerStellarAccountTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { ok, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  export function registerStellarAccountTool(server) {
@@ -15,7 +16,7 @@ export function registerStellarAccountTool(server) {
15
16
  logger.debug({ address }, "stellar-account invoked");
16
17
  try {
17
18
  const config = loadOrCreateWallet();
18
- const res = await fetch(`${config.apiUrl}/stellar-account?address=${encodeURIComponent(address)}`);
19
+ const res = await apiFetch(config, `/stellar-account?address=${encodeURIComponent(address)}`);
19
20
  if (!res.ok) {
20
21
  const body = await res.text();
21
22
  return err(`Account lookup error ${res.status}: ${body}`);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerStellarAssetTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { ok, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  export function registerStellarAssetTool(server) {
@@ -16,7 +17,7 @@ export function registerStellarAssetTool(server) {
16
17
  logger.debug({ asset }, "stellar-asset invoked");
17
18
  try {
18
19
  const config = loadOrCreateWallet();
19
- const res = await fetch(`${config.apiUrl}/stellar-asset?asset=${encodeURIComponent(asset)}`);
20
+ const res = await apiFetch(config, `/stellar-asset?asset=${encodeURIComponent(asset)}`);
20
21
  if (!res.ok) {
21
22
  const body = await res.text();
22
23
  return err(`Asset lookup error ${res.status}: ${body}`);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerStellarPoolsTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { ok, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  export function registerStellarPoolsTool(server) {
@@ -25,7 +26,7 @@ export function registerStellarPoolsTool(server) {
25
26
  const params = new URLSearchParams({ limit: String(limit) });
26
27
  if (asset)
27
28
  params.set("asset", asset);
28
- const res = await fetch(`${config.apiUrl}/stellar-pools?${params}`);
29
+ const res = await apiFetch(config, `/stellar-pools?${params}`);
29
30
  if (!res.ok) {
30
31
  const body = await res.text();
31
32
  return err(`Pools error ${res.status}: ${body}`);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerStocksTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { okPaid, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  import { TOOL_PRICES } from "../lib/config.js";
@@ -18,7 +19,7 @@ export function registerStocksTool(server) {
18
19
  return withCache("stocks", { symbol }, () => withBudget("stocks", async () => {
19
20
  try {
20
21
  const config = loadOrCreateWallet();
21
- const res = await fetch(`${config.apiUrl}/stocks?symbol=${encodeURIComponent(symbol)}`);
22
+ const res = await apiFetch(config, `/stocks?symbol=${encodeURIComponent(symbol)}`);
22
23
  if (!res.ok) {
23
24
  const body = await res.text();
24
25
  return err(`Stocks API error ${res.status}: ${body}`);
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerSwapQuoteTool(server: McpServer): void;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { loadOrCreateWallet } from "../lib/wallet.js";
3
+ import { apiFetch } from "../lib/api-fetch.js";
3
4
  import { ok, err } from "../lib/format.js";
4
5
  import { logger } from "../lib/logger.js";
5
6
  export function registerSwapQuoteTool(server) {
@@ -22,7 +23,7 @@ export function registerSwapQuoteTool(server) {
22
23
  try {
23
24
  const config = loadOrCreateWallet();
24
25
  const params = new URLSearchParams({ from, to, amount, mode });
25
- const res = await fetch(`${config.apiUrl}/swap-quote?${params}`);
26
+ const res = await apiFetch(config, `/swap-quote?${params}`);
26
27
  if (!res.ok) {
27
28
  const body = await res.text();
28
29
  return err(`Swap quote error ${res.status}: ${body}`);