omnitrade-mcp 0.3.2 → 0.4.1
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 +238 -189
- package/dist/index.js +1 -1
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -5,255 +5,310 @@ import { existsSync, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
|
5
5
|
import { homedir } from "os";
|
|
6
6
|
import { join } from "path";
|
|
7
7
|
import * as readline from "readline";
|
|
8
|
-
var VERSION = "0.
|
|
8
|
+
var VERSION = "0.4.1";
|
|
9
9
|
var CONFIG_PATH = join(homedir(), ".omnitrade", "config.json");
|
|
10
|
-
var
|
|
10
|
+
var c = {
|
|
11
11
|
reset: "\x1B[0m",
|
|
12
|
-
|
|
12
|
+
bold: "\x1B[1m",
|
|
13
13
|
dim: "\x1B[2m",
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
white: "\x1B[97m",
|
|
15
|
+
gray: "\x1B[90m",
|
|
16
|
+
blue: "\x1B[38;5;39m",
|
|
17
|
+
cyan: "\x1B[38;5;51m",
|
|
18
|
+
green: "\x1B[38;5;46m",
|
|
19
|
+
yellow: "\x1B[38;5;226m",
|
|
20
|
+
purple: "\x1B[38;5;165m",
|
|
21
|
+
orange: "\x1B[38;5;208m",
|
|
22
|
+
red: "\x1B[38;5;196m"
|
|
23
23
|
};
|
|
24
|
-
var c = COLORS;
|
|
25
24
|
function printLogo() {
|
|
26
25
|
console.log(`
|
|
27
|
-
${c.cyan}
|
|
28
|
-
\
|
|
29
|
-
\
|
|
30
|
-
\
|
|
31
|
-
\
|
|
32
|
-
\
|
|
33
|
-
\
|
|
34
|
-
\
|
|
35
|
-
\
|
|
36
|
-
\
|
|
37
|
-
\
|
|
38
|
-
\
|
|
39
|
-
\
|
|
40
|
-
\
|
|
41
|
-
\
|
|
42
|
-
\
|
|
43
|
-
\u2551 \u2551
|
|
44
|
-
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
|
|
26
|
+
${c.cyan}
|
|
27
|
+
\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584\u2584
|
|
28
|
+
\u2588${c.reset} ${c.cyan}\u2588
|
|
29
|
+
\u2588${c.reset} ${c.white}${c.bold} \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588 \u2588\u2588\u2588 \u2588\u2588\u2588 \u2588\u2588 \u2588\u2588${c.purple}\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588${c.white}\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 ${c.reset}${c.cyan} \u2588
|
|
30
|
+
\u2588${c.reset} ${c.white}${c.bold}\u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588${c.purple} \u2588\u2588 ${c.white}\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ${c.reset}${c.cyan} \u2588
|
|
31
|
+
\u2588${c.reset} ${c.white}${c.bold}\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588${c.purple} \u2588\u2588 ${c.white}\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588 ${c.reset}${c.cyan} \u2588
|
|
32
|
+
\u2588${c.reset} ${c.white}${c.bold}\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588${c.purple} \u2588\u2588 ${c.white}\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 ${c.reset}${c.cyan} \u2588
|
|
33
|
+
\u2588${c.reset} ${c.white}${c.bold} \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588${c.purple} \u2588\u2588 ${c.white}\u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588\u2588\u2588 ${c.reset}${c.cyan} \u2588
|
|
34
|
+
\u2588${c.reset} ${c.cyan}\u2588
|
|
35
|
+
\u2588${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${c.cyan}\u2588
|
|
36
|
+
\u2588${c.reset} ${c.cyan}\u2588
|
|
37
|
+
\u2588${c.reset} ${c.white}One AI. ${c.cyan}107 Exchanges. ${c.purple}Natural Language Trading.${c.reset} ${c.cyan}\u2588
|
|
38
|
+
\u2588${c.reset} ${c.cyan}\u2588
|
|
39
|
+
\u2588${c.reset} ${c.gray}v${VERSION}${c.reset} ${c.gray}by Connectry Labs${c.reset} ${c.cyan}\u2588
|
|
40
|
+
\u2588${c.reset} ${c.cyan}\u2588
|
|
41
|
+
\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580\u2580
|
|
45
42
|
${c.reset}`);
|
|
46
43
|
}
|
|
44
|
+
function printCompactLogo() {
|
|
45
|
+
console.log(`
|
|
46
|
+
${c.cyan}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${c.reset}
|
|
47
|
+
${c.white}${c.bold}OMNITRADE${c.purple} MCP${c.reset} ${c.gray}\u2022 One AI. 107 Exchanges.${c.reset}
|
|
48
|
+
${c.cyan}\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501${c.reset}
|
|
49
|
+
`);
|
|
50
|
+
}
|
|
47
51
|
function printHelp() {
|
|
48
52
|
printLogo();
|
|
49
53
|
console.log(`
|
|
50
|
-
${c.
|
|
51
|
-
|
|
54
|
+
${c.white}${c.bold}COMMANDS${c.reset}
|
|
55
|
+
${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}
|
|
52
56
|
|
|
53
|
-
${c.
|
|
54
|
-
${c.
|
|
55
|
-
${c.
|
|
56
|
-
${c.
|
|
57
|
-
${c.
|
|
58
|
-
${c.
|
|
59
|
-
${c.green}help${c.reset} Show this help message
|
|
60
|
-
${c.green}version${c.reset} Show version
|
|
57
|
+
${c.green}${c.bold}setup${c.reset} Guided setup wizard ${c.dim}(start here!)${c.reset}
|
|
58
|
+
${c.cyan}start${c.reset} Start MCP server for Claude Desktop
|
|
59
|
+
${c.cyan}test${c.reset} Test your exchange connections
|
|
60
|
+
${c.cyan}config${c.reset} View current configuration
|
|
61
|
+
${c.cyan}exchanges${c.reset} List all 107 supported exchanges
|
|
62
|
+
${c.cyan}help${c.reset} Show this help
|
|
61
63
|
|
|
62
|
-
${c.
|
|
63
|
-
|
|
64
|
-
${c.cyan}omnitrade-mcp init${c.reset}
|
|
64
|
+
${c.white}${c.bold}GET STARTED${c.reset}
|
|
65
|
+
${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}
|
|
65
66
|
|
|
66
|
-
${c.
|
|
67
|
-
${c.cyan}omnitrade-mcp start${c.reset}
|
|
67
|
+
${c.yellow}$${c.reset} ${c.green}omnitrade setup${c.reset}
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
${c.white}${c.bold}DOCUMENTATION${c.reset}
|
|
70
|
+
${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}
|
|
71
71
|
|
|
72
|
-
${c.bright}${c.white}CONFIGURATION${c.reset}
|
|
73
|
-
Config file: ${c.yellow}~/.omnitrade/config.json${c.reset}
|
|
74
|
-
|
|
75
|
-
${c.bright}${c.white}DOCUMENTATION${c.reset}
|
|
76
72
|
${c.blue}https://github.com/Connectry-io/omnitrade-mcp${c.reset}
|
|
77
73
|
|
|
78
|
-
${c.bright}${c.white}SUPPORT${c.reset}
|
|
79
|
-
${c.blue}https://github.com/Connectry-io/omnitrade-mcp/issues${c.reset}
|
|
80
74
|
`);
|
|
81
75
|
}
|
|
82
|
-
function
|
|
83
|
-
console.log(`${c.cyan}omnitrade-mcp${c.reset} v${VERSION}`);
|
|
84
|
-
}
|
|
85
|
-
async function showExchanges() {
|
|
76
|
+
async function runSetupWizard() {
|
|
86
77
|
printLogo();
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
78
|
+
const rl = readline.createInterface({
|
|
79
|
+
input: process.stdin,
|
|
80
|
+
output: process.stdout
|
|
81
|
+
});
|
|
82
|
+
const question = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
83
|
+
console.log(`
|
|
84
|
+
${c.white}${c.bold}WELCOME TO OMNITRADE${c.reset}
|
|
85
|
+
${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}
|
|
86
|
+
|
|
87
|
+
Let's connect your first crypto exchange to Claude.
|
|
88
|
+
This takes about ${c.green}2 minutes${c.reset}.
|
|
89
|
+
|
|
90
|
+
${c.white}${c.bold}WHAT YOU NEED${c.reset}
|
|
91
|
+
|
|
92
|
+
${c.cyan}1.${c.reset} A crypto exchange account ${c.dim}(Binance, Coinbase, etc.)${c.reset}
|
|
93
|
+
${c.cyan}2.${c.reset} API keys from that exchange
|
|
94
|
+
${c.cyan}3.${c.reset} Claude Desktop installed
|
|
95
|
+
|
|
90
96
|
`);
|
|
91
|
-
|
|
92
|
-
console.log(`${c.green}${c.bright}\u2605 TIER 1 - CERTIFIED${c.reset}`);
|
|
93
|
-
console.log(` ${tier1.filter((e) => exchanges.includes(e)).join(", ")}`);
|
|
94
|
-
const tier2 = ["coinbase", "kraken", "bitstamp", "gemini", "bitfinex", "poloniex", "deribit", "upbit", "bithumb", "bitvavo", "phemex", "ascendex", "lbank"];
|
|
97
|
+
await question(` ${c.dim}Press Enter to continue...${c.reset}`);
|
|
95
98
|
console.log(`
|
|
96
|
-
${c.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
+
${c.white}${c.bold}STEP 1/4 \u2014 CHOOSE EXCHANGE${c.reset}
|
|
100
|
+
${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}
|
|
101
|
+
|
|
102
|
+
${c.cyan}[1]${c.reset} Binance ${c.dim}Largest global exchange${c.reset}
|
|
103
|
+
${c.cyan}[2]${c.reset} Coinbase ${c.dim}US-based, beginner friendly${c.reset}
|
|
104
|
+
${c.cyan}[3]${c.reset} Kraken ${c.dim}Security focused${c.reset}
|
|
105
|
+
${c.cyan}[4]${c.reset} Bybit ${c.dim}Derivatives trading${c.reset}
|
|
106
|
+
${c.cyan}[5]${c.reset} OKX ${c.dim}Full-featured${c.reset}
|
|
107
|
+
${c.cyan}[6]${c.reset} KuCoin ${c.dim}Altcoin variety${c.reset}
|
|
108
|
+
${c.cyan}[7]${c.reset} Other ${c.dim}Enter name manually${c.reset}
|
|
109
|
+
|
|
110
|
+
`);
|
|
111
|
+
const exchangeChoice = await question(` ${c.yellow}?${c.reset} Select [1-7]: `);
|
|
112
|
+
const exchangeMap = {
|
|
113
|
+
"1": "binance",
|
|
114
|
+
"2": "coinbase",
|
|
115
|
+
"3": "kraken",
|
|
116
|
+
"4": "bybit",
|
|
117
|
+
"5": "okx",
|
|
118
|
+
"6": "kucoin"
|
|
119
|
+
};
|
|
120
|
+
let exchange = exchangeMap[exchangeChoice.trim()];
|
|
121
|
+
if (!exchange) {
|
|
122
|
+
exchange = await question(` ${c.yellow}?${c.reset} Exchange name: `);
|
|
123
|
+
}
|
|
124
|
+
exchange = exchange.toLowerCase().trim();
|
|
99
125
|
console.log(`
|
|
100
|
-
${c.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
126
|
+
${c.white}${c.bold}STEP 2/4 \u2014 GET API KEYS${c.reset}
|
|
127
|
+
${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}
|
|
128
|
+
|
|
129
|
+
Create API keys on ${c.white}${c.bold}${exchange.toUpperCase()}${c.reset}:
|
|
130
|
+
`);
|
|
131
|
+
if (exchange === "binance") {
|
|
132
|
+
console.log(`
|
|
133
|
+
${c.cyan}1.${c.reset} Go to ${c.blue}https://testnet.binance.vision${c.reset} ${c.dim}(testnet)${c.reset}
|
|
134
|
+
${c.cyan}2.${c.reset} Click ${c.white}"Generate HMAC_SHA256 Key"${c.reset}
|
|
135
|
+
${c.cyan}3.${c.reset} Permissions: ${c.green}\u2713 Read${c.reset} ${c.green}\u2713 Trade${c.reset} ${c.red}\u2717 Withdraw${c.reset}
|
|
136
|
+
${c.cyan}4.${c.reset} Copy ${c.white}API Key${c.reset} and ${c.white}Secret Key${c.reset}
|
|
137
|
+
`);
|
|
138
|
+
} else if (exchange === "coinbase") {
|
|
139
|
+
console.log(`
|
|
140
|
+
${c.cyan}1.${c.reset} Go to ${c.blue}https://portal.cdp.coinbase.com${c.reset}
|
|
141
|
+
${c.cyan}2.${c.reset} Create a new project
|
|
142
|
+
${c.cyan}3.${c.reset} Generate API credentials
|
|
143
|
+
${c.cyan}4.${c.reset} Copy ${c.white}API Key${c.reset}, ${c.white}Secret${c.reset}, and ${c.white}Passphrase${c.reset}
|
|
144
|
+
`);
|
|
145
|
+
} else {
|
|
146
|
+
console.log(`
|
|
147
|
+
${c.cyan}1.${c.reset} Log into ${c.white}${exchange}${c.reset}
|
|
148
|
+
${c.cyan}2.${c.reset} Go to API settings
|
|
149
|
+
${c.cyan}3.${c.reset} Create new API key
|
|
150
|
+
${c.cyan}4.${c.reset} Enable: ${c.green}\u2713 Read${c.reset} ${c.green}\u2713 Trade${c.reset} ${c.red}\u2717 Withdraw${c.reset}
|
|
151
|
+
`);
|
|
105
152
|
}
|
|
153
|
+
console.log(` ${c.orange}\u26A0 Never enable withdrawal permissions!${c.reset}
|
|
154
|
+
`);
|
|
155
|
+
await question(` ${c.dim}Press Enter when you have your keys...${c.reset}`);
|
|
106
156
|
console.log(`
|
|
107
|
-
${c.
|
|
157
|
+
${c.white}${c.bold}STEP 3/4 \u2014 ENTER API KEYS${c.reset}
|
|
158
|
+
${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}
|
|
159
|
+
|
|
160
|
+
${c.dim}Keys are stored locally at ~/.omnitrade/config.json${c.reset}
|
|
161
|
+
${c.dim}They never leave your machine.${c.reset}
|
|
162
|
+
|
|
163
|
+
`);
|
|
164
|
+
const apiKey = await question(` ${c.yellow}?${c.reset} API Key: `);
|
|
165
|
+
const secret = await question(` ${c.yellow}?${c.reset} Secret: `);
|
|
166
|
+
let password = "";
|
|
167
|
+
if (["coinbase", "kucoin", "okx"].includes(exchange)) {
|
|
168
|
+
password = await question(` ${c.yellow}?${c.reset} Passphrase: `);
|
|
169
|
+
}
|
|
170
|
+
const testnetAnswer = await question(` ${c.yellow}?${c.reset} Use testnet? ${c.dim}(Y/n)${c.reset}: `);
|
|
171
|
+
const testnet = testnetAnswer.toLowerCase() !== "n";
|
|
172
|
+
rl.close();
|
|
173
|
+
const config = {
|
|
174
|
+
exchanges: {
|
|
175
|
+
[exchange]: {
|
|
176
|
+
apiKey: apiKey.trim(),
|
|
177
|
+
secret: secret.trim(),
|
|
178
|
+
...password.trim() ? { password: password.trim() } : {},
|
|
179
|
+
testnet
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
security: {
|
|
183
|
+
maxOrderSize: 100,
|
|
184
|
+
confirmTrades: true
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
const configDir = join(homedir(), ".omnitrade");
|
|
188
|
+
if (!existsSync(configDir)) {
|
|
189
|
+
mkdirSync(configDir, { recursive: true });
|
|
190
|
+
}
|
|
191
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
192
|
+
try {
|
|
193
|
+
const { chmodSync } = await import("fs");
|
|
194
|
+
chmodSync(CONFIG_PATH, 384);
|
|
195
|
+
} catch {
|
|
196
|
+
}
|
|
197
|
+
console.log(`
|
|
198
|
+
${c.green}${c.bold}\u2713 SAVED${c.reset}
|
|
199
|
+
|
|
200
|
+
${c.white}${c.bold}STEP 4/4 \u2014 CONNECT TO CLAUDE${c.reset}
|
|
201
|
+
${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}
|
|
202
|
+
|
|
203
|
+
${c.cyan}1.${c.reset} Open Claude Desktop config:
|
|
204
|
+
|
|
205
|
+
${c.dim}macOS:${c.reset} ${c.blue}~/Library/Application Support/Claude/claude_desktop_config.json${c.reset}
|
|
206
|
+
${c.dim}Windows:${c.reset} ${c.blue}%APPDATA%\\Claude\\claude_desktop_config.json${c.reset}
|
|
207
|
+
|
|
208
|
+
${c.cyan}2.${c.reset} Add this:
|
|
209
|
+
|
|
210
|
+
${c.gray}{
|
|
211
|
+
"mcpServers": {
|
|
212
|
+
"omnitrade": {
|
|
213
|
+
"command": "omnitrade",
|
|
214
|
+
"args": ["start"]
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}${c.reset}
|
|
218
|
+
|
|
219
|
+
${c.cyan}3.${c.reset} ${c.white}Restart Claude Desktop${c.reset}
|
|
220
|
+
|
|
221
|
+
${c.cyan}4.${c.reset} Try asking Claude:
|
|
222
|
+
${c.dim}"What's my balance on ${exchange}?"${c.reset}
|
|
223
|
+
|
|
224
|
+
${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}
|
|
225
|
+
|
|
226
|
+
${c.white}${c.bold}USEFUL COMMANDS${c.reset}
|
|
227
|
+
|
|
228
|
+
${c.cyan}omnitrade test${c.reset} Test your connection
|
|
229
|
+
${c.cyan}omnitrade config${c.reset} View configuration
|
|
230
|
+
${c.cyan}omnitrade setup${c.reset} Add another exchange
|
|
231
|
+
|
|
232
|
+
${c.green}${c.bold}\u2713 Setup complete!${c.reset}
|
|
233
|
+
|
|
108
234
|
`);
|
|
109
235
|
}
|
|
110
|
-
async function
|
|
111
|
-
|
|
112
|
-
|
|
236
|
+
async function showExchanges() {
|
|
237
|
+
printCompactLogo();
|
|
238
|
+
const ccxt = await import("ccxt");
|
|
239
|
+
const exchanges = ccxt.default.exchanges;
|
|
240
|
+
console.log(` ${c.white}${c.bold}SUPPORTED EXCHANGES${c.reset} ${c.dim}(${exchanges.length})${c.reset}
|
|
113
241
|
`);
|
|
114
|
-
|
|
242
|
+
const tier1 = ["binance", "bybit", "okx", "gate", "kucoin", "bitget", "htx", "mexc", "cryptocom", "bitmex"];
|
|
243
|
+
const tier2 = ["coinbase", "kraken", "bitstamp", "gemini", "bitfinex", "poloniex", "deribit", "upbit", "bithumb", "bitvavo"];
|
|
244
|
+
console.log(` ${c.green}\u2605 TIER 1${c.reset} ${c.dim}${tier1.join(", ")}${c.reset}`);
|
|
245
|
+
console.log(` ${c.yellow}\u2605 TIER 2${c.reset} ${c.dim}${tier2.join(", ")}${c.reset}`);
|
|
246
|
+
const others = exchanges.filter((e) => !tier1.includes(e) && !tier2.includes(e));
|
|
247
|
+
console.log(` ${c.gray}+ ${others.length} more...${c.reset}
|
|
115
248
|
`);
|
|
249
|
+
}
|
|
250
|
+
async function showConfig() {
|
|
251
|
+
printCompactLogo();
|
|
116
252
|
if (!existsSync(CONFIG_PATH)) {
|
|
117
|
-
console.log(
|
|
118
|
-
|
|
119
|
-
Run ${c.cyan}omnitrade-mcp init${c.reset} to create one.
|
|
253
|
+
console.log(` ${c.red}\u2717 No configuration${c.reset}
|
|
254
|
+
Run ${c.cyan}omnitrade setup${c.reset}
|
|
120
255
|
`);
|
|
121
256
|
return;
|
|
122
257
|
}
|
|
123
258
|
try {
|
|
124
259
|
const config = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
125
|
-
|
|
126
|
-
console.log(`${c.green}\u2713 Config loaded${c.reset}
|
|
260
|
+
console.log(` ${c.green}\u2713 Config loaded${c.reset} ${c.dim}${CONFIG_PATH}${c.reset}
|
|
127
261
|
`);
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const cfg = config.exchanges[ex];
|
|
131
|
-
const mode = cfg.testnet ? `${c.yellow}testnet${c.reset}` : `${c.green}production${c.reset}`;
|
|
262
|
+
for (const [ex, cfg] of Object.entries(config.exchanges || {})) {
|
|
263
|
+
const mode = cfg.testnet ? `${c.yellow}testnet${c.reset}` : `${c.green}live${c.reset}`;
|
|
132
264
|
console.log(` ${c.cyan}\u2022${c.reset} ${ex} (${mode})`);
|
|
133
265
|
}
|
|
134
|
-
if (config.security) {
|
|
135
|
-
console.log(`
|
|
136
|
-
${c.bright}Security settings:${c.reset}`);
|
|
137
|
-
if (config.security.maxOrderSize) {
|
|
138
|
-
console.log(` ${c.cyan}\u2022${c.reset} Max order size: $${config.security.maxOrderSize}`);
|
|
139
|
-
}
|
|
140
|
-
if (config.security.allowedPairs) {
|
|
141
|
-
console.log(` ${c.cyan}\u2022${c.reset} Allowed pairs: ${config.security.allowedPairs.join(", ")}`);
|
|
142
|
-
}
|
|
143
|
-
if (config.security.testnetOnly) {
|
|
144
|
-
console.log(` ${c.cyan}\u2022${c.reset} Testnet only: ${c.yellow}enabled${c.reset}`);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
266
|
console.log("");
|
|
148
267
|
} catch (error) {
|
|
149
|
-
console.log(
|
|
268
|
+
console.log(` ${c.red}\u2717 Error:${c.reset} ${error.message}
|
|
150
269
|
`);
|
|
151
270
|
}
|
|
152
271
|
}
|
|
153
272
|
async function testConnections() {
|
|
154
|
-
|
|
155
|
-
console.log(`${c.bright}${c.white}TESTING CONNECTIONS${c.reset}
|
|
156
|
-
`);
|
|
273
|
+
printCompactLogo();
|
|
157
274
|
if (!existsSync(CONFIG_PATH)) {
|
|
158
|
-
console.log(
|
|
159
|
-
|
|
160
|
-
Run ${c.cyan}omnitrade-mcp init${c.reset} to create one.
|
|
275
|
+
console.log(` ${c.red}\u2717 No configuration${c.reset}
|
|
276
|
+
Run ${c.cyan}omnitrade setup${c.reset}
|
|
161
277
|
`);
|
|
162
278
|
return;
|
|
163
279
|
}
|
|
280
|
+
console.log(` ${c.white}${c.bold}TESTING${c.reset}
|
|
281
|
+
`);
|
|
164
282
|
const ccxt = await import("ccxt");
|
|
165
283
|
const config = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
process.stdout.write(` Testing ${c.cyan}${name}${c.reset}... `);
|
|
284
|
+
for (const [name, cfg] of Object.entries(config.exchanges || {})) {
|
|
285
|
+
process.stdout.write(` ${c.cyan}${name}${c.reset} ... `);
|
|
169
286
|
try {
|
|
170
287
|
const ExchangeClass = ccxt.default[name];
|
|
171
|
-
if (!ExchangeClass) {
|
|
172
|
-
console.log(`${c.red}\u2717 Unknown exchange${c.reset}`);
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
288
|
const ex = new ExchangeClass({
|
|
176
289
|
apiKey: cfg.apiKey,
|
|
177
290
|
secret: cfg.secret,
|
|
178
291
|
password: cfg.password,
|
|
179
292
|
enableRateLimit: true
|
|
180
293
|
});
|
|
181
|
-
if (cfg.testnet)
|
|
182
|
-
ex.setSandboxMode(true);
|
|
183
|
-
}
|
|
294
|
+
if (cfg.testnet) ex.setSandboxMode(true);
|
|
184
295
|
const balance = await ex.fetchBalance();
|
|
185
|
-
const assets = Object.entries(balance.total).filter(([_, v]) => v > 0).slice(0, 3).map(([k, v]) => `${k}
|
|
186
|
-
|
|
187
|
-
console.log(`${c.green}\u2713${c.reset} Connected (${mode})`);
|
|
188
|
-
if (assets) {
|
|
189
|
-
console.log(` ${c.dim}Balances: ${assets}${c.reset}`);
|
|
190
|
-
}
|
|
296
|
+
const assets = Object.entries(balance.total).filter(([_, v]) => v > 0).slice(0, 3).map(([k, v]) => `${k}:${v}`).join(" ");
|
|
297
|
+
console.log(`${c.green}\u2713${c.reset} ${c.dim}${assets || "connected"}${c.reset}`);
|
|
191
298
|
} catch (error) {
|
|
192
|
-
console.log(`${c.red}\u2717 ${error.message.
|
|
299
|
+
console.log(`${c.red}\u2717${c.reset} ${c.dim}${error.message.slice(0, 40)}${c.reset}`);
|
|
193
300
|
}
|
|
194
301
|
}
|
|
195
302
|
console.log("");
|
|
196
303
|
}
|
|
197
|
-
async function initConfig() {
|
|
198
|
-
printLogo();
|
|
199
|
-
console.log(`${c.bright}${c.white}SETUP WIZARD${c.reset}
|
|
200
|
-
`);
|
|
201
|
-
const rl = readline.createInterface({
|
|
202
|
-
input: process.stdin,
|
|
203
|
-
output: process.stdout
|
|
204
|
-
});
|
|
205
|
-
const question = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
206
|
-
console.log(`${c.dim}Let's set up your first exchange connection.${c.reset}
|
|
207
|
-
`);
|
|
208
|
-
const exchange = await question(`${c.cyan}?${c.reset} Exchange name (e.g., binance, coinbase, kraken): `);
|
|
209
|
-
if (!exchange.trim()) {
|
|
210
|
-
console.log(`${c.red}\u2717 Exchange name required${c.reset}`);
|
|
211
|
-
rl.close();
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
const apiKey = await question(`${c.cyan}?${c.reset} API Key: `);
|
|
215
|
-
const secret = await question(`${c.cyan}?${c.reset} Secret Key: `);
|
|
216
|
-
const password = await question(`${c.cyan}?${c.reset} Passphrase (press Enter if none): `);
|
|
217
|
-
const testnetAnswer = await question(`${c.cyan}?${c.reset} Use testnet/sandbox? (Y/n): `);
|
|
218
|
-
const testnet = testnetAnswer.toLowerCase() !== "n";
|
|
219
|
-
rl.close();
|
|
220
|
-
const config = {
|
|
221
|
-
exchanges: {
|
|
222
|
-
[exchange.toLowerCase().trim()]: {
|
|
223
|
-
apiKey: apiKey.trim(),
|
|
224
|
-
secret: secret.trim(),
|
|
225
|
-
...password.trim() ? { password: password.trim() } : {},
|
|
226
|
-
testnet
|
|
227
|
-
}
|
|
228
|
-
},
|
|
229
|
-
security: {
|
|
230
|
-
maxOrderSize: 100,
|
|
231
|
-
confirmTrades: true
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
const configDir = join(homedir(), ".omnitrade");
|
|
235
|
-
if (!existsSync(configDir)) {
|
|
236
|
-
mkdirSync(configDir, { recursive: true });
|
|
237
|
-
}
|
|
238
|
-
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
239
|
-
try {
|
|
240
|
-
const { chmodSync } = await import("fs");
|
|
241
|
-
chmodSync(CONFIG_PATH, 384);
|
|
242
|
-
} catch {
|
|
243
|
-
}
|
|
244
|
-
console.log(`
|
|
245
|
-
${c.green}\u2713 Configuration saved to ${CONFIG_PATH}${c.reset}`);
|
|
246
|
-
console.log(`
|
|
247
|
-
${c.bright}Next steps:${c.reset}`);
|
|
248
|
-
console.log(` 1. Test connection: ${c.cyan}omnitrade-mcp test${c.reset}`);
|
|
249
|
-
console.log(` 2. Add to Claude: ${c.cyan}Add "omnitrade-mcp" to Claude Desktop config${c.reset}`);
|
|
250
|
-
console.log(` 3. Start trading: ${c.cyan}Ask Claude "What's my balance?"${c.reset}
|
|
251
|
-
`);
|
|
252
|
-
}
|
|
253
304
|
async function main() {
|
|
254
305
|
const args = process.argv.slice(2);
|
|
255
306
|
const command = args[0] || "help";
|
|
256
307
|
switch (command) {
|
|
308
|
+
case "setup":
|
|
309
|
+
case "init":
|
|
310
|
+
await runSetupWizard();
|
|
311
|
+
break;
|
|
257
312
|
case "help":
|
|
258
313
|
case "--help":
|
|
259
314
|
case "-h":
|
|
@@ -262,31 +317,25 @@ async function main() {
|
|
|
262
317
|
case "version":
|
|
263
318
|
case "--version":
|
|
264
319
|
case "-v":
|
|
265
|
-
|
|
320
|
+
console.log(`omnitrade v${VERSION}`);
|
|
266
321
|
break;
|
|
267
322
|
case "exchanges":
|
|
268
323
|
case "list":
|
|
269
324
|
await showExchanges();
|
|
270
325
|
break;
|
|
271
326
|
case "config":
|
|
272
|
-
case "status":
|
|
273
327
|
await showConfig();
|
|
274
328
|
break;
|
|
275
329
|
case "test":
|
|
276
330
|
await testConnections();
|
|
277
331
|
break;
|
|
278
|
-
case "init":
|
|
279
|
-
case "setup":
|
|
280
|
-
await initConfig();
|
|
281
|
-
break;
|
|
282
332
|
case "start":
|
|
283
333
|
case "serve":
|
|
284
|
-
case "run":
|
|
285
334
|
await import("./index.js");
|
|
286
335
|
break;
|
|
287
336
|
default:
|
|
288
|
-
console.log(`${c.red}Unknown
|
|
289
|
-
|
|
337
|
+
console.log(`${c.red}Unknown: ${command}${c.reset}
|
|
338
|
+
Run ${c.cyan}omnitrade help${c.reset}
|
|
290
339
|
`);
|
|
291
340
|
process.exit(1);
|
|
292
341
|
}
|
package/dist/index.js
CHANGED
|
@@ -911,7 +911,7 @@ function registerArbitrageTools(server, exchangeManager) {
|
|
|
911
911
|
}
|
|
912
912
|
|
|
913
913
|
// src/index.ts
|
|
914
|
-
var VERSION = "0.
|
|
914
|
+
var VERSION = "0.4.1";
|
|
915
915
|
function showBanner() {
|
|
916
916
|
console.error(`
|
|
917
917
|
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omnitrade-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "Multi-exchange AI trading via MCP. 107 exchanges. One AI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
|
+
"omnitrade": "dist/cli.js",
|
|
8
9
|
"omnitrade-mcp": "dist/cli.js"
|
|
9
10
|
},
|
|
10
11
|
"scripts": {
|