omnitrade-mcp 0.4.3 → 0.5.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.
- package/dist/cli.js +79 -18
- package/dist/index.js +54 -9
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -198,29 +198,90 @@ async function runSetupWizard() {
|
|
|
198
198
|
|
|
199
199
|
${c.white}${c.bold}STEP 4/4 \u2014 CONNECT TO CLAUDE${c.reset}
|
|
200
200
|
${c.gray}\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${c.reset}
|
|
201
|
-
|
|
201
|
+
`);
|
|
202
|
+
const rl2 = readline.createInterface({
|
|
203
|
+
input: process.stdin,
|
|
204
|
+
output: process.stdout
|
|
205
|
+
});
|
|
206
|
+
const question2 = (q) => new Promise((resolve) => rl2.question(q, resolve));
|
|
207
|
+
const platform = process.platform;
|
|
208
|
+
let claudeConfigPath;
|
|
209
|
+
if (platform === "darwin") {
|
|
210
|
+
claudeConfigPath = join(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
211
|
+
} else if (platform === "win32") {
|
|
212
|
+
claudeConfigPath = join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json");
|
|
213
|
+
} else {
|
|
214
|
+
claudeConfigPath = join(homedir(), ".config", "Claude", "claude_desktop_config.json");
|
|
215
|
+
}
|
|
216
|
+
const configureAuto = await question2(` ${c.yellow}?${c.reset} Auto-configure Claude Desktop? ${c.dim}(Y/n)${c.reset}: `);
|
|
217
|
+
if (configureAuto.toLowerCase() !== "n") {
|
|
218
|
+
try {
|
|
219
|
+
let claudeConfig = {};
|
|
220
|
+
const claudeConfigDir = join(claudeConfigPath, "..");
|
|
221
|
+
if (existsSync(claudeConfigPath)) {
|
|
222
|
+
claudeConfig = JSON.parse(readFileSync(claudeConfigPath, "utf-8"));
|
|
223
|
+
console.log(` ${c.dim}Found existing config${c.reset}`);
|
|
224
|
+
} else {
|
|
225
|
+
if (!existsSync(claudeConfigDir)) {
|
|
226
|
+
mkdirSync(claudeConfigDir, { recursive: true });
|
|
227
|
+
}
|
|
228
|
+
console.log(` ${c.dim}Creating new config${c.reset}`);
|
|
229
|
+
}
|
|
230
|
+
if (!claudeConfig.mcpServers) {
|
|
231
|
+
claudeConfig.mcpServers = {};
|
|
232
|
+
}
|
|
233
|
+
claudeConfig.mcpServers.omnitrade = {
|
|
234
|
+
command: "omnitrade",
|
|
235
|
+
args: ["start"]
|
|
236
|
+
};
|
|
237
|
+
writeFileSync(claudeConfigPath, JSON.stringify(claudeConfig, null, 2));
|
|
238
|
+
console.log(`
|
|
239
|
+
${c.green}${c.bold}\u2713 Claude Desktop configured!${c.reset}
|
|
240
|
+
${c.dim}${claudeConfigPath}${c.reset}
|
|
241
|
+
`);
|
|
242
|
+
if (platform === "darwin") {
|
|
243
|
+
const restart = await question2(` ${c.yellow}?${c.reset} Restart Claude Desktop now? ${c.dim}(Y/n)${c.reset}: `);
|
|
244
|
+
if (restart.toLowerCase() !== "n") {
|
|
245
|
+
const { execSync } = await import("child_process");
|
|
246
|
+
try {
|
|
247
|
+
execSync(`osascript -e 'quit app "Claude"'`, { stdio: "ignore" });
|
|
248
|
+
await new Promise((r) => setTimeout(r, 1e3));
|
|
249
|
+
execSync('open -a "Claude"', { stdio: "ignore" });
|
|
250
|
+
console.log(` ${c.green}\u2713 Claude Desktop restarted${c.reset}`);
|
|
251
|
+
} catch {
|
|
252
|
+
console.log(` ${c.yellow}! Please restart Claude Desktop manually${c.reset}`);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
} else {
|
|
256
|
+
console.log(` ${c.yellow}!${c.reset} Please restart Claude Desktop to apply changes`);
|
|
257
|
+
}
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.log(` ${c.red}\u2717 Auto-config failed:${c.reset} ${error.message}`);
|
|
260
|
+
console.log(`
|
|
261
|
+
${c.dim}Manual setup:${c.reset}
|
|
262
|
+
1. Open: ${c.blue}${claudeConfigPath}${c.reset}
|
|
263
|
+
2. Add omnitrade to mcpServers
|
|
264
|
+
3. Restart Claude Desktop
|
|
265
|
+
`);
|
|
266
|
+
}
|
|
267
|
+
} else {
|
|
268
|
+
console.log(`
|
|
202
269
|
${c.cyan}1.${c.reset} Open Claude Desktop config:
|
|
270
|
+
${c.blue}${claudeConfigPath}${c.reset}
|
|
203
271
|
|
|
204
|
-
|
|
205
|
-
${c.
|
|
206
|
-
|
|
207
|
-
${c.cyan}2.${c.reset} Add this:
|
|
272
|
+
${c.cyan}2.${c.reset} Add this to mcpServers:
|
|
273
|
+
${c.gray}"omnitrade": { "command": "omnitrade", "args": ["start"] }${c.reset}
|
|
208
274
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
}${c.reset}
|
|
217
|
-
|
|
218
|
-
${c.cyan}3.${c.reset} ${c.white}Restart Claude Desktop${c.reset}
|
|
275
|
+
${c.cyan}3.${c.reset} Restart Claude Desktop
|
|
276
|
+
`);
|
|
277
|
+
}
|
|
278
|
+
rl2.close();
|
|
279
|
+
console.log(`
|
|
280
|
+
${c.gray}\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${c.reset}
|
|
219
281
|
|
|
220
|
-
${c.
|
|
221
|
-
${c.dim}"What's my balance on ${exchange}?"${c.reset}
|
|
282
|
+
${c.white}${c.bold}TRY IT${c.reset}
|
|
222
283
|
|
|
223
|
-
|
|
284
|
+
Ask Claude: ${c.dim}"What's my balance on ${exchange}?"${c.reset}
|
|
224
285
|
|
|
225
286
|
${c.white}${c.bold}USEFUL COMMANDS${c.reset}
|
|
226
287
|
|
package/dist/index.js
CHANGED
|
@@ -292,9 +292,12 @@ function registerBalanceTools(server, exchangeManager) {
|
|
|
292
292
|
);
|
|
293
293
|
server.tool(
|
|
294
294
|
"get_portfolio",
|
|
295
|
-
"Get a unified portfolio summary
|
|
296
|
-
{
|
|
297
|
-
|
|
295
|
+
"Get a unified portfolio summary with USD values. Shows total portfolio worth and individual holdings.",
|
|
296
|
+
{
|
|
297
|
+
minValue: z2.number().default(1).describe("Minimum USD value to display (default: $1). Set to 0 to show all."),
|
|
298
|
+
showAll: z2.boolean().default(false).describe("Show all assets including dust (overrides minValue)")
|
|
299
|
+
},
|
|
300
|
+
async ({ minValue, showAll }) => {
|
|
298
301
|
const assetTotals = {};
|
|
299
302
|
const errors = [];
|
|
300
303
|
for (const [name, ex] of exchangeManager.getAll()) {
|
|
@@ -313,17 +316,59 @@ function registerBalanceTools(server, exchangeManager) {
|
|
|
313
316
|
errors.push(`${name}: ${error.message}`);
|
|
314
317
|
}
|
|
315
318
|
}
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
319
|
+
const priceCache = {};
|
|
320
|
+
const stablecoins = ["USDT", "USDC", "BUSD", "DAI", "USD", "TUSD", "USDP"];
|
|
321
|
+
const priceExchange = exchangeManager.getAll().values().next().value;
|
|
322
|
+
if (priceExchange) {
|
|
323
|
+
for (const symbol of Object.keys(assetTotals)) {
|
|
324
|
+
if (stablecoins.includes(symbol.toUpperCase())) {
|
|
325
|
+
priceCache[symbol] = 1;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
try {
|
|
329
|
+
const ticker = await priceExchange.fetchTicker(`${symbol}/USDT`);
|
|
330
|
+
if (ticker.last) {
|
|
331
|
+
priceCache[symbol] = ticker.last;
|
|
332
|
+
}
|
|
333
|
+
} catch {
|
|
334
|
+
try {
|
|
335
|
+
const ticker = await priceExchange.fetchTicker(`${symbol}/USD`);
|
|
336
|
+
if (ticker.last) {
|
|
337
|
+
priceCache[symbol] = ticker.last;
|
|
338
|
+
}
|
|
339
|
+
} catch {
|
|
340
|
+
priceCache[symbol] = 0;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const assets = Object.entries(assetTotals).map(([asset, data]) => {
|
|
346
|
+
const price = priceCache[asset] ?? 0;
|
|
347
|
+
const usdValue = data.total * price;
|
|
348
|
+
return {
|
|
349
|
+
asset,
|
|
350
|
+
quantity: data.total,
|
|
351
|
+
price,
|
|
352
|
+
usdValue: parseFloat(usdValue.toFixed(2)),
|
|
353
|
+
distribution: data.byExchange
|
|
354
|
+
};
|
|
355
|
+
}).filter((a) => showAll || a.usdValue >= minValue).sort((a, b) => b.usdValue - a.usdValue);
|
|
356
|
+
const totalUsdValue = assets.reduce((sum, a) => sum + a.usdValue, 0);
|
|
357
|
+
const hiddenCount = Object.keys(assetTotals).length - assets.length;
|
|
321
358
|
const portfolio = {
|
|
322
359
|
summary: {
|
|
360
|
+
totalValue: `$${totalUsdValue.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`,
|
|
323
361
|
totalAssets: assets.length,
|
|
362
|
+
hiddenAssets: hiddenCount > 0 ? `${hiddenCount} assets below $${minValue}` : void 0,
|
|
324
363
|
exchanges: exchangeManager.getNames()
|
|
325
364
|
},
|
|
326
|
-
assets
|
|
365
|
+
holdings: assets.map((a) => ({
|
|
366
|
+
asset: a.asset,
|
|
367
|
+
quantity: a.quantity,
|
|
368
|
+
price: a.price > 0 ? `$${a.price.toLocaleString("en-US")}` : "N/A",
|
|
369
|
+
value: `$${a.usdValue.toLocaleString("en-US", { minimumFractionDigits: 2 })}`,
|
|
370
|
+
percent: totalUsdValue > 0 ? `${(a.usdValue / totalUsdValue * 100).toFixed(1)}%` : "0%"
|
|
371
|
+
})),
|
|
327
372
|
errors: errors.length > 0 ? errors : void 0
|
|
328
373
|
};
|
|
329
374
|
return {
|