@xlmtools/cli 0.1.2 → 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 (66) hide show
  1. package/README.md +18 -12
  2. package/dist/cli.d.ts +2 -0
  3. package/{src/lib/api-fetch.ts → dist/lib/api-fetch.d.ts} +3 -14
  4. package/dist/lib/budget.d.ts +14 -0
  5. package/dist/lib/cache.d.ts +7 -0
  6. package/dist/lib/config.d.ts +2 -0
  7. package/dist/lib/format.d.ts +15 -0
  8. package/dist/lib/logger.d.ts +2 -0
  9. package/dist/lib/wallet.d.ts +9 -0
  10. package/dist/server.d.ts +22 -0
  11. package/dist/server.js +89 -0
  12. package/dist/tools/budget.d.ts +2 -0
  13. package/dist/tools/crypto.d.ts +2 -0
  14. package/dist/tools/dex-candles.d.ts +2 -0
  15. package/dist/tools/dex-orderbook.d.ts +2 -0
  16. package/dist/tools/dex-trades.d.ts +2 -0
  17. package/dist/tools/domain.d.ts +2 -0
  18. package/dist/tools/image.d.ts +2 -0
  19. package/dist/tools/oracle-price.d.ts +2 -0
  20. package/dist/tools/research.d.ts +2 -0
  21. package/dist/tools/scrape.d.ts +2 -0
  22. package/dist/tools/screenshot.d.ts +2 -0
  23. package/dist/tools/search.d.ts +2 -0
  24. package/dist/tools/stellar-account.d.ts +2 -0
  25. package/dist/tools/stellar-asset.d.ts +2 -0
  26. package/dist/tools/stellar-pools.d.ts +2 -0
  27. package/dist/tools/stocks.d.ts +2 -0
  28. package/dist/tools/swap-quote.d.ts +2 -0
  29. package/dist/tools/tools-list.d.ts +2 -0
  30. package/dist/tools/wallet-tool.d.ts +2 -0
  31. package/dist/tools/weather.d.ts +2 -0
  32. package/dist/tools/youtube.d.ts +2 -0
  33. package/package.json +27 -3
  34. package/dist/index.js +0 -77
  35. package/dist/tools/card.js +0 -51
  36. package/dist/tools/reddit.js +0 -40
  37. package/src/cli.ts +0 -245
  38. package/src/index.ts +0 -90
  39. package/src/lib/budget.ts +0 -78
  40. package/src/lib/cache.ts +0 -66
  41. package/src/lib/config.ts +0 -18
  42. package/src/lib/format.ts +0 -51
  43. package/src/lib/logger.ts +0 -6
  44. package/src/lib/wallet.ts +0 -143
  45. package/src/tools/budget.ts +0 -67
  46. package/src/tools/crypto.ts +0 -26
  47. package/src/tools/dex-candles.ts +0 -53
  48. package/src/tools/dex-orderbook.ts +0 -47
  49. package/src/tools/dex-trades.ts +0 -52
  50. package/src/tools/domain.ts +0 -25
  51. package/src/tools/image.ts +0 -50
  52. package/src/tools/oracle-price.ts +0 -43
  53. package/src/tools/research.ts +0 -49
  54. package/src/tools/scrape.ts +0 -43
  55. package/src/tools/screenshot.ts +0 -48
  56. package/src/tools/search.ts +0 -49
  57. package/src/tools/stellar-account.ts +0 -40
  58. package/src/tools/stellar-asset.ts +0 -41
  59. package/src/tools/stellar-pools.ts +0 -46
  60. package/src/tools/stocks.ts +0 -45
  61. package/src/tools/swap-quote.ts +0 -44
  62. package/src/tools/tools-list.ts +0 -22
  63. package/src/tools/wallet-tool.ts +0 -51
  64. package/src/tools/weather.ts +0 -25
  65. package/src/tools/youtube.ts +0 -51
  66. package/tsconfig.json +0 -13
package/src/cli.ts DELETED
@@ -1,245 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { Mppx } from "mppx/client";
4
- import { stellar } from "@stellar/mpp/charge/client";
5
- import { Horizon } from "@stellar/stellar-sdk";
6
- import { loadOrCreateWallet, getKeypair } from "./lib/wallet.js";
7
- import { apiFetch } from "./lib/api-fetch.js";
8
- import { TOOL_PRICES } from "./lib/config.js";
9
- import { logger } from "./lib/logger.js";
10
-
11
- // ── Arg parsing ──────────────────────────────────────────
12
-
13
- function parseArgs(argv: string[]) {
14
- const [tool, ...rest] = argv;
15
- const positional: string[] = [];
16
- const flags: Record<string, string> = {};
17
-
18
- for (let i = 0; i < rest.length; i++) {
19
- if (rest[i].startsWith("--") && i + 1 < rest.length) {
20
- const key = rest[i].slice(2).replace(/-/g, "_");
21
- flags[key] = rest[i + 1];
22
- i++;
23
- } else {
24
- positional.push(rest[i]);
25
- }
26
- }
27
-
28
- return { tool: tool ?? "", positional, flags };
29
- }
30
-
31
- // ── URL builder ──────────────────────────────────────────
32
-
33
- function buildRequest(
34
- base: string,
35
- tool: string,
36
- pos: string[],
37
- flags: Record<string, string>,
38
- ): { url: string; init: RequestInit } {
39
- const p = new URLSearchParams();
40
-
41
- // Map each tool to its API endpoint + params
42
- const toolMap: Record<string, () => { path: string; method?: string; body?: string }> = {
43
- search: () => { p.set("q", pos[0] ?? ""); if (flags.count) p.set("count", flags.count); return { path: "/search" }; },
44
- research: () => { p.set("q", pos[0] ?? ""); if (flags.num_results) p.set("num_results", flags.num_results); return { path: "/research" }; },
45
- youtube: () => { if (flags.id) p.set("id", flags.id); else p.set("q", pos[0] ?? flags.query ?? ""); return { path: "/youtube" }; },
46
- screenshot: () => { p.set("url", pos[0] ?? ""); if (flags.format) p.set("format", flags.format); return { path: "/screenshot" }; },
47
- scrape: () => { p.set("url", pos[0] ?? ""); return { path: "/scrape" }; },
48
- image: () => ({ path: "/image", method: "POST", body: JSON.stringify({ prompt: pos[0] ?? "", size: flags.size ?? "1024x1024" }) }),
49
- stocks: () => { p.set("symbol", pos[0] ?? ""); return { path: "/stocks" }; },
50
- crypto: () => { p.set("ids", pos[0] ?? ""); if (flags.vs_currency) p.set("vs_currency", flags.vs_currency); return { path: "/crypto" }; },
51
- weather: () => { p.set("location", pos[0] ?? ""); return { path: "/weather" }; },
52
- domain: () => { p.set("name", pos[0] ?? ""); return { path: "/domain" }; },
53
- "dex-orderbook": () => { p.set("pair", pos[0] ?? ""); if (flags.limit) p.set("limit", flags.limit); return { path: "/dex-orderbook" }; },
54
- "dex-candles": () => { p.set("pair", pos[0] ?? ""); if (flags.resolution) p.set("resolution", flags.resolution); if (flags.limit) p.set("limit", flags.limit); return { path: "/dex-candles" }; },
55
- "dex-trades": () => { p.set("pair", pos[0] ?? ""); if (flags.limit) p.set("limit", flags.limit); if (flags.trade_type) p.set("trade_type", flags.trade_type); return { path: "/dex-trades" }; },
56
- "swap-quote": () => { p.set("from", pos[0] ?? flags.from ?? ""); p.set("to", pos[1] ?? flags.to ?? ""); p.set("amount", pos[2] ?? flags.amount ?? ""); if (flags.mode) p.set("mode", flags.mode); return { path: "/swap-quote" }; },
57
- "stellar-asset": () => { p.set("asset", pos[0] ?? ""); return { path: "/stellar-asset" }; },
58
- "stellar-account": () => { p.set("address", pos[0] ?? ""); return { path: "/stellar-account" }; },
59
- "stellar-pools": () => { if (pos[0] || flags.asset) p.set("asset", pos[0] ?? flags.asset ?? ""); if (flags.limit) p.set("limit", flags.limit); return { path: "/stellar-pools" }; },
60
- "oracle-price": () => { p.set("asset", pos[0] ?? ""); if (flags.feed) p.set("feed", flags.feed); return { path: "/oracle-price" }; },
61
- };
62
-
63
- const builder = toolMap[tool];
64
- if (!builder) {
65
- process.stderr.write(`Unknown tool: ${tool}\nRun xlm --help for available tools.\n`);
66
- process.exit(1);
67
- }
68
-
69
- const { path, method, body } = builder();
70
- const qs = p.toString();
71
- const url = qs ? `${base}${path}?${qs}` : `${base}${path}`;
72
- const init: RequestInit = { method: method ?? "GET" };
73
- if (body) {
74
- init.headers = { "Content-Type": "application/json" };
75
- init.body = body;
76
- }
77
-
78
- return { url, init };
79
- }
80
-
81
- // ── Local tool handlers ──────────────────────────────────
82
-
83
- async function handleWallet(publicKey: string) {
84
- const server = new Horizon.Server("https://horizon-testnet.stellar.org");
85
- try {
86
- const account = await server.loadAccount(publicKey);
87
- const xlm = account.balances.find(
88
- (b: Horizon.HorizonApi.BalanceLine) => b.asset_type === "native",
89
- );
90
- const usdc = account.balances.find(
91
- (b: Horizon.HorizonApi.BalanceLine) =>
92
- "asset_code" in b && b.asset_code === "USDC",
93
- );
94
- return {
95
- address: publicKey,
96
- network: "stellar:testnet",
97
- xlm_balance: xlm?.balance ?? "0",
98
- usdc_balance: usdc && "balance" in usdc ? usdc.balance : "0",
99
- };
100
- } catch {
101
- return {
102
- address: publicKey,
103
- network: "stellar:testnet",
104
- xlm_balance: "0",
105
- usdc_balance: "0",
106
- note: "Account not funded yet",
107
- };
108
- }
109
- }
110
-
111
- function handleTools() {
112
- const paid = Object.entries(TOOL_PRICES).map(([name, price]) => ({
113
- name,
114
- price: `$${price}`,
115
- }));
116
- // Note: `budget` is MCP-only — the CLI is a fresh process per invocation
117
- // so a session-scoped cap is meaningless. Excluded from the CLI's free list.
118
- const free = [
119
- "crypto", "weather", "domain", "wallet", "tools",
120
- "dex-orderbook", "dex-candles", "dex-trades", "swap-quote",
121
- "stellar-asset", "stellar-account", "stellar-pools", "oracle-price",
122
- ];
123
- return { paid, free, network: "stellar:testnet", payment: "MPP / USDC" };
124
- }
125
-
126
- // ── Help text ────────────────────────────────────────────
127
-
128
- const HELP = `XLMTools CLI — Stellar-native tools with pay-per-call
129
-
130
- Usage: xlm <tool> [args] [--flag value]
131
-
132
- Paid tools ($0.001-$0.04 USDC via Stellar MPP):
133
- search <query> [--count N] Web search
134
- research <query> [--num-results N] Deep research
135
- youtube <query> | --id <id> YouTube search/lookup
136
- screenshot <url> [--format png] Capture URL screenshot
137
- scrape <url> Extract text from URL
138
- image <prompt> [--size 1024x1024] AI image generation
139
- stocks <symbol> Stock quotes
140
-
141
- Free tools:
142
- crypto <ids> [--vs-currency usd] Crypto prices
143
- weather <location> Current weather
144
- domain <name> Domain availability
145
- dex-orderbook <pair> [--limit N] Stellar DEX orderbook
146
- dex-candles <pair> OHLCV candlesticks
147
- dex-trades <pair> Recent DEX trades
148
- swap-quote <from> <to> <amount> DEX swap pathfinding
149
- stellar-asset <asset> Asset info
150
- stellar-account <address> Account lookup
151
- stellar-pools [--asset X] Liquidity pools
152
- oracle-price <asset> [--feed crypto] Oracle prices
153
- wallet Your Stellar wallet
154
- tools List all tools
155
-
156
- Examples:
157
- xlm search "Stellar MPP micropayments"
158
- xlm crypto bitcoin,ethereum,stellar
159
- xlm weather Lagos
160
- xlm stocks AAPL
161
- xlm dex-orderbook XLM/USDC --limit 5
162
- xlm wallet
163
- `;
164
-
165
- // ── Main ─────────────────────────────────────────────────
166
-
167
- async function main() {
168
- const args = process.argv.slice(2);
169
-
170
- if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
171
- process.stdout.write(HELP);
172
- return;
173
- }
174
-
175
- const { tool, positional, flags } = parseArgs(args);
176
-
177
- // Init wallet + mppx (payment handling)
178
- const config = loadOrCreateWallet();
179
- const keypair = getKeypair(config);
180
-
181
- Mppx.create({
182
- methods: [
183
- stellar.charge({
184
- keypair,
185
- mode: "pull",
186
- onProgress(event) {
187
- logger.debug({ eventType: event.type }, "MPP payment event");
188
- },
189
- }),
190
- ],
191
- });
192
-
193
- // ── Local tools (no API call needed) ──
194
-
195
- if (tool === "wallet") {
196
- const data = await handleWallet(config.stellarPublicKey);
197
- console.log(JSON.stringify(data, null, 2));
198
- return;
199
- }
200
-
201
- if (tool === "tools") {
202
- console.log(JSON.stringify(handleTools(), null, 2));
203
- return;
204
- }
205
-
206
- // ── API tools ──
207
-
208
- const isPaid = tool in TOOL_PRICES;
209
- const { url, init } = buildRequest(config.apiUrl, tool, positional, flags);
210
-
211
- if (isPaid) {
212
- process.stderr.write(` Tool: ${tool} · Cost: $${TOOL_PRICES[tool]} USDC\n`);
213
- }
214
-
215
- // Route through apiFetch so the X-XLMTools-Client header (and any
216
- // future cross-cutting concerns like retries / user-agent) are
217
- // applied consistently with the MCP tools. apiFetch detects the
218
- // full-URL form and passes it straight through.
219
- const res = await apiFetch(config, url, init);
220
-
221
- if (!res.ok) {
222
- const text = await res.text();
223
- process.stderr.write(`Error ${res.status}: ${text}\n`);
224
- process.exit(1);
225
- }
226
-
227
- const data = (await res.json()) as Record<string, unknown>;
228
-
229
- // Print receipt footer for paid tools
230
- if (isPaid && data.receipt) {
231
- const { receipt, ...rest } = data;
232
- const r = receipt as { tx_hash: string; amount: string; currency: string; network: string };
233
- console.log(JSON.stringify(rest, null, 2));
234
- const hash = r.tx_hash.length > 16 ? r.tx_hash.slice(0, 16) + "..." : r.tx_hash;
235
- const network = r.network === "stellar:testnet" ? "stellar testnet" : r.network;
236
- process.stderr.write(`\n Payment: $${r.amount} ${r.currency} · tx/${hash} · ${network}\n`);
237
- } else {
238
- console.log(JSON.stringify(data, null, 2));
239
- }
240
- }
241
-
242
- main().catch((e) => {
243
- logger.error({ err: e }, "CLI fatal error");
244
- process.exit(1);
245
- });
package/src/index.ts DELETED
@@ -1,90 +0,0 @@
1
- #!/usr/bin/env node
2
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import { Mppx } from "mppx/client";
5
- import { stellar } from "@stellar/mpp/charge/client";
6
- import { loadOrCreateWallet, getKeypair } from "./lib/wallet.js";
7
- import { logger } from "./lib/logger.js";
8
- import { registerCryptoTool } from "./tools/crypto.js";
9
- import { registerWeatherTool } from "./tools/weather.js";
10
- import { registerDomainTool } from "./tools/domain.js";
11
- import { registerToolsListTool } from "./tools/tools-list.js";
12
- import { registerWalletTool } from "./tools/wallet-tool.js";
13
- import { registerSearchTool } from "./tools/search.js";
14
- import { registerResearchTool } from "./tools/research.js";
15
-
16
- import { registerYoutubeTool } from "./tools/youtube.js";
17
- import { registerScreenshotTool } from "./tools/screenshot.js";
18
- import { registerScrapeTool } from "./tools/scrape.js";
19
- import { registerImageTool } from "./tools/image.js";
20
- import { registerStocksTool } from "./tools/stocks.js";
21
- import { registerDexOrderbookTool } from "./tools/dex-orderbook.js";
22
- import { registerDexCandlesTool } from "./tools/dex-candles.js";
23
- import { registerDexTradesTool } from "./tools/dex-trades.js";
24
- import { registerSwapQuoteTool } from "./tools/swap-quote.js";
25
- import { registerStellarAssetTool } from "./tools/stellar-asset.js";
26
- import { registerStellarAccountTool } from "./tools/stellar-account.js";
27
- import { registerStellarPoolsTool } from "./tools/stellar-pools.js";
28
- import { registerOraclePriceTool } from "./tools/oracle-price.js";
29
- import { registerBudgetTool } from "./tools/budget.js";
30
-
31
- const config = loadOrCreateWallet();
32
- const keypair = getKeypair(config);
33
-
34
- // Mppx polyfills global fetch to auto-handle 402 payments
35
- Mppx.create({
36
- methods: [
37
- stellar.charge({
38
- keypair,
39
- mode: "pull",
40
- onProgress(event) {
41
- logger.debug({ eventType: event.type }, "MPP payment event");
42
- },
43
- }),
44
- ],
45
- });
46
-
47
- // { logging: {} } enables ctx.mcpReq.log() in tool handlers
48
- const server = new McpServer(
49
- { name: "xlmtools", version: "0.1.0" },
50
- { capabilities: { tools: {}, logging: {} } }
51
- );
52
-
53
- // Free tools
54
- registerCryptoTool(server);
55
- registerWeatherTool(server);
56
- registerDomainTool(server);
57
- registerToolsListTool(server);
58
- registerWalletTool(server);
59
- registerBudgetTool(server);
60
-
61
- // Paid tools
62
- registerSearchTool(server);
63
- registerResearchTool(server);
64
-
65
- registerYoutubeTool(server);
66
- registerScreenshotTool(server);
67
- registerScrapeTool(server);
68
- registerImageTool(server);
69
- registerStocksTool(server);
70
-
71
- // Stellar-native tools (free)
72
- registerDexOrderbookTool(server);
73
- registerDexCandlesTool(server);
74
- registerDexTradesTool(server);
75
- registerSwapQuoteTool(server);
76
- registerStellarAssetTool(server);
77
- registerStellarAccountTool(server);
78
- registerStellarPoolsTool(server);
79
- registerOraclePriceTool(server);
80
-
81
- async function main() {
82
- const transport = new StdioServerTransport();
83
- await server.connect(transport);
84
- logger.info("XLMTools MCP server running");
85
- }
86
-
87
- main().catch((error) => {
88
- logger.error({ err: error }, "Fatal error");
89
- process.exit(1);
90
- });
package/src/lib/budget.ts DELETED
@@ -1,78 +0,0 @@
1
- import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
- import { err } from "./format.js";
3
- import { TOOL_PRICES } from "./config.js";
4
- import { logger } from "./logger.js";
5
-
6
- // Session-scoped budget state (resets on MCP server restart)
7
- let maxBudget: number | null = null;
8
- let totalSpent = 0;
9
-
10
- export function setBudget(max: number): void {
11
- maxBudget = max;
12
- // Reset spent counter so the new cap starts fresh. Users expect
13
- // "I just set a $1.00 budget" to mean they have $1.00 to spend
14
- // from now — not "$1.00 minus whatever I spent before setting it".
15
- totalSpent = 0;
16
- logger.info({ max }, "session budget set");
17
- }
18
-
19
- export function clearBudget(): void {
20
- maxBudget = null;
21
- totalSpent = 0;
22
- logger.info("session budget cleared");
23
- }
24
-
25
- export function getStatus(): {
26
- max: number | null;
27
- spent: number;
28
- remaining: number | null;
29
- } {
30
- return {
31
- max: maxBudget,
32
- spent: Math.round(totalSpent * 1000) / 1000,
33
- remaining:
34
- maxBudget !== null
35
- ? Math.round((maxBudget - totalSpent) * 1000) / 1000
36
- : null,
37
- };
38
- }
39
-
40
- function canSpend(amount: number): boolean {
41
- if (maxBudget === null) return true;
42
- // Round to 3 decimal places to avoid floating-point drift
43
- const spent = Math.round(totalSpent * 1000) / 1000;
44
- return spent + amount <= maxBudget;
45
- }
46
-
47
- function recordSpend(amount: number): void {
48
- totalSpent += amount;
49
- logger.debug({ amount, totalSpent }, "spend recorded");
50
- }
51
-
52
- /**
53
- * Wrap a paid tool call with budget checking.
54
- * If budget would be exceeded, returns an error without calling the API.
55
- * On success, records the spend.
56
- */
57
- export async function withBudget(
58
- toolName: string,
59
- fn: () => Promise<CallToolResult>,
60
- ): Promise<CallToolResult> {
61
- const price = parseFloat(TOOL_PRICES[toolName] ?? "0");
62
- if (!canSpend(price)) {
63
- const status = getStatus();
64
- return err(
65
- `Budget limit reached. This call costs $${TOOL_PRICES[toolName]} ` +
66
- `but only $${status.remaining?.toFixed(3)} remains. ` +
67
- `Use the budget tool to check or adjust your limit.`,
68
- );
69
- }
70
-
71
- const result = await fn();
72
-
73
- if (!result.isError) {
74
- recordSpend(price);
75
- }
76
-
77
- return result;
78
- }
package/src/lib/cache.ts DELETED
@@ -1,66 +0,0 @@
1
- import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
- import { logger } from "./logger.js";
3
-
4
- const TTL_MS = 5 * 60 * 1000; // 5 minutes
5
-
6
- interface CacheEntry {
7
- result: CallToolResult;
8
- expires: number;
9
- }
10
-
11
- const store = new Map<string, CacheEntry>();
12
-
13
- /**
14
- * Wrap a tool call with response caching.
15
- * Identical tool+params within the TTL return the cached result
16
- * with no API call and no payment.
17
- */
18
- export async function withCache(
19
- toolName: string,
20
- params: Record<string, unknown>,
21
- fn: () => Promise<CallToolResult>,
22
- ): Promise<CallToolResult> {
23
- const key = `${toolName}:${JSON.stringify(params)}`;
24
-
25
- const cached = store.get(key);
26
- if (cached && Date.now() < cached.expires) {
27
- logger.debug({ toolName }, "cache hit");
28
-
29
- const original = cached.result;
30
- if (original.content[0]?.type === "text") {
31
- // Strip the "---\nPayment: ..." footer from cached text — no
32
- // payment happened on this call, so the original tx hash would
33
- // contradict the [cached — no charge] prefix.
34
- const stripped = original.content[0].text.replace(
35
- /\n---\nPayment: .*$/s,
36
- "",
37
- );
38
- return {
39
- ...original,
40
- content: [
41
- {
42
- type: "text" as const,
43
- text: `[cached — no charge]\n\n${stripped}`,
44
- },
45
- ],
46
- };
47
- }
48
- return original;
49
- }
50
-
51
- const result = await fn();
52
-
53
- if (!result.isError) {
54
- store.set(key, { result, expires: Date.now() + TTL_MS });
55
- }
56
-
57
- // Evict expired entries periodically
58
- if (store.size > 50) {
59
- const now = Date.now();
60
- for (const [k, v] of store) {
61
- if (now >= v.expires) store.delete(k);
62
- }
63
- }
64
-
65
- return result;
66
- }
package/src/lib/config.ts DELETED
@@ -1,18 +0,0 @@
1
- export const TOOL_PRICES: Record<string, string> = {
2
- search: "0.003",
3
- research: "0.010",
4
-
5
- youtube: "0.002",
6
- screenshot: "0.010",
7
- scrape: "0.002",
8
- image: "0.040",
9
- stocks: "0.001",
10
- };
11
-
12
- export const FREE_TOOLS = new Set([
13
- "crypto", "weather", "domain", "wallet", "tools",
14
- // Stellar-native tools (free — Horizon + StellarExpert + Reflector are public APIs)
15
- "dex-orderbook", "dex-candles", "dex-trades",
16
- "swap-quote", "stellar-asset", "stellar-account",
17
- "stellar-pools", "oracle-price",
18
- ]);
package/src/lib/format.ts DELETED
@@ -1,51 +0,0 @@
1
- import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
-
3
- export interface ReceiptInfo {
4
- tx_hash: string;
5
- amount: string;
6
- currency: string;
7
- network: string;
8
- }
9
-
10
- function formatReceipt(receipt: ReceiptInfo): string {
11
- const hashShort = receipt.tx_hash.length > 12
12
- ? receipt.tx_hash.slice(0, 12) + "..."
13
- : receipt.tx_hash;
14
- const network = receipt.network === "stellar:testnet" ? "stellar testnet" : receipt.network;
15
- return `\n---\nPayment: $${receipt.amount} ${receipt.currency} \u00b7 tx/${hashShort} \u00b7 ${network}`;
16
- }
17
-
18
- export function ok(data: unknown): CallToolResult {
19
- return {
20
- content: [{ type: "text", text: JSON.stringify(data, null, 2) }],
21
- isError: false,
22
- };
23
- }
24
-
25
- /**
26
- * Format a paid tool response, appending a receipt line if present.
27
- * Strips the receipt from the data to avoid cluttering the JSON output,
28
- * then appends a human-readable payment line.
29
- */
30
- export function okPaid(data: Record<string, unknown>): CallToolResult {
31
- const receipt = data.receipt as ReceiptInfo | undefined;
32
- if (!receipt) {
33
- return ok(data);
34
- }
35
-
36
- // Strip receipt from the JSON data — show it as a footer instead
37
- const { receipt: _, ...rest } = data;
38
- const text = JSON.stringify(rest, null, 2) + formatReceipt(receipt);
39
-
40
- return {
41
- content: [{ type: "text", text }],
42
- isError: false,
43
- };
44
- }
45
-
46
- export function err(message: string): CallToolResult {
47
- return {
48
- content: [{ type: "text", text: `Error: ${message}` }],
49
- isError: true,
50
- };
51
- }
package/src/lib/logger.ts DELETED
@@ -1,6 +0,0 @@
1
- import pino from "pino";
2
-
3
- export const logger = pino(
4
- { name: "xlmtools", level: process.env.LOG_LEVEL ?? "info" },
5
- pino.destination(2)
6
- );