omnitrade-mcp 0.3.1 → 0.4.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 +271 -154
- package/dist/index.js +1 -1
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -5,159 +5,331 @@ 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.0";
|
|
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
|
-
blue
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
italic: "\x1B[3m",
|
|
15
|
+
// Subtle colors
|
|
16
|
+
white: "\x1B[97m",
|
|
17
|
+
gray: "\x1B[90m",
|
|
18
|
+
blue: "\x1B[38;5;75m",
|
|
19
|
+
// Soft blue
|
|
20
|
+
cyan: "\x1B[38;5;80m",
|
|
21
|
+
// Soft cyan
|
|
22
|
+
green: "\x1B[38;5;114m",
|
|
23
|
+
// Soft green
|
|
24
|
+
yellow: "\x1B[38;5;222m",
|
|
25
|
+
// Soft yellow
|
|
26
|
+
purple: "\x1B[38;5;141m",
|
|
27
|
+
// Soft purple
|
|
28
|
+
orange: "\x1B[38;5;215m",
|
|
29
|
+
// Soft orange
|
|
30
|
+
red: "\x1B[38;5;203m"
|
|
31
|
+
// Soft red
|
|
23
32
|
};
|
|
24
|
-
var c = COLORS;
|
|
25
33
|
function printLogo() {
|
|
26
34
|
console.log(`
|
|
27
|
-
${c.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
\
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
\
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
|
35
|
+
${c.blue}${c.bold}
|
|
36
|
+
\u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E
|
|
37
|
+
\u2502 \u2502
|
|
38
|
+
\u2502 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557${c.purple}\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557${c.blue}\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2502
|
|
39
|
+
\u2502 \u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551${c.purple}\u255A\u2550\u2550\u2588\u2588\u2554\u2550\u2550\u255D${c.blue}\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2502
|
|
40
|
+
\u2502 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2551${c.purple} \u2588\u2588\u2551 ${c.blue}\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u2502
|
|
41
|
+
\u2502 \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2551${c.purple} \u2588\u2588\u2551 ${c.blue}\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2502
|
|
42
|
+
\u2502 \u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551${c.purple} \u2588\u2588\u2551 ${c.blue}\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2502
|
|
43
|
+
\u2502 \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u255D${c.purple} \u255A\u2550\u255D ${c.blue}\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u2502
|
|
44
|
+
\u2502 \u2502
|
|
45
|
+
\u2502 ${c.gray}\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.blue} \u2502
|
|
46
|
+
\u2502 \u2502
|
|
47
|
+
\u2502 ${c.white}One AI. 107 Exchanges. Natural Language Trading.${c.blue} \u2502
|
|
48
|
+
\u2502 \u2502
|
|
49
|
+
\u2502 ${c.gray}v${VERSION} by Connectry Labs${c.blue} \u2502
|
|
50
|
+
\u2502 \u2502
|
|
51
|
+
\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F
|
|
45
52
|
${c.reset}`);
|
|
46
53
|
}
|
|
54
|
+
function printCompactLogo() {
|
|
55
|
+
console.log(`
|
|
56
|
+
${c.blue}${c.bold} \u256D\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256E
|
|
57
|
+
\u2502 ${c.white}OmniTrade${c.purple} MCP${c.blue} ${c.gray}\xB7 One AI. 107 Exchanges.${c.blue} \u2502
|
|
58
|
+
\u2570\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F${c.reset}
|
|
59
|
+
`);
|
|
60
|
+
}
|
|
47
61
|
function printHelp() {
|
|
48
62
|
printLogo();
|
|
49
63
|
console.log(`
|
|
50
|
-
${c.
|
|
51
|
-
|
|
64
|
+
${c.white}${c.bold} COMMANDS${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\u2500\u2500\u2500${c.reset}
|
|
52
66
|
|
|
53
|
-
${c.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
${c.green}help${c.reset} Show this help message
|
|
60
|
-
${c.green}version${c.reset} Show version
|
|
67
|
+
${c.green}setup${c.reset} Guided setup wizard ${c.dim}(recommended for first use)${c.reset}
|
|
68
|
+
${c.blue}start${c.reset} Start the MCP server for Claude Desktop
|
|
69
|
+
${c.blue}test${c.reset} Test your exchange connections
|
|
70
|
+
${c.blue}config${c.reset} View current configuration
|
|
71
|
+
${c.blue}exchanges${c.reset} List all 107 supported exchanges
|
|
72
|
+
${c.blue}help${c.reset} Show this help message
|
|
61
73
|
|
|
62
|
-
${c.
|
|
63
|
-
|
|
64
|
-
${c.cyan}omnitrade-mcp init${c.reset}
|
|
74
|
+
${c.white}${c.bold} QUICK START${c.reset}
|
|
75
|
+
${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\u2500\u2500\u2500${c.reset}
|
|
65
76
|
|
|
66
|
-
|
|
67
|
-
${c.cyan}omnitrade-mcp start${c.reset}
|
|
77
|
+
${c.yellow}$${c.reset} ${c.cyan}omnitrade setup${c.reset} ${c.dim}Run the guided setup wizard${c.reset}
|
|
68
78
|
|
|
69
|
-
|
|
70
|
-
|
|
79
|
+
${c.white}${c.bold} LINKS${c.reset}
|
|
80
|
+
${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\u2500\u2500\u2500${c.reset}
|
|
71
81
|
|
|
72
|
-
${c.
|
|
73
|
-
|
|
82
|
+
${c.dim}Documentation${c.reset} ${c.blue}https://github.com/Connectry-io/omnitrade-mcp${c.reset}
|
|
83
|
+
${c.dim}Issues${c.reset} ${c.blue}https://github.com/Connectry-io/omnitrade-mcp/issues${c.reset}
|
|
74
84
|
|
|
75
|
-
${c.bright}${c.white}DOCUMENTATION${c.reset}
|
|
76
|
-
${c.blue}https://github.com/Connectry-io/omnitrade-mcp${c.reset}
|
|
77
|
-
|
|
78
|
-
${c.bright}${c.white}SUPPORT${c.reset}
|
|
79
|
-
${c.blue}https://github.com/Connectry-io/omnitrade-mcp/issues${c.reset}
|
|
80
85
|
`);
|
|
81
86
|
}
|
|
82
|
-
function
|
|
83
|
-
|
|
87
|
+
async function runSetupWizard() {
|
|
88
|
+
printLogo();
|
|
89
|
+
const rl = readline.createInterface({
|
|
90
|
+
input: process.stdin,
|
|
91
|
+
output: process.stdout
|
|
92
|
+
});
|
|
93
|
+
const question = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
94
|
+
const clear = () => console.log("\x1B[2J\x1B[H");
|
|
95
|
+
console.log(`
|
|
96
|
+
${c.white}${c.bold} WELCOME TO OMNITRADE${c.reset}
|
|
97
|
+
${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\u2500\u2500\u2500${c.reset}
|
|
98
|
+
|
|
99
|
+
This wizard will help you connect your first cryptocurrency exchange
|
|
100
|
+
to Claude. It takes about ${c.green}2 minutes${c.reset}.
|
|
101
|
+
|
|
102
|
+
${c.white}${c.bold} WHAT YOU'LL NEED${c.reset}
|
|
103
|
+
${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\u2500\u2500\u2500${c.reset}
|
|
104
|
+
|
|
105
|
+
${c.cyan}1.${c.reset} An account on a cryptocurrency exchange ${c.dim}(Binance, Coinbase, etc.)${c.reset}
|
|
106
|
+
${c.cyan}2.${c.reset} API keys from that exchange ${c.dim}(we'll show you how)${c.reset}
|
|
107
|
+
${c.cyan}3.${c.reset} Claude Desktop installed ${c.dim}(download from claude.ai)${c.reset}
|
|
108
|
+
|
|
109
|
+
${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\u2500\u2500\u2500${c.reset}
|
|
110
|
+
`);
|
|
111
|
+
await question(` ${c.dim}Press Enter to continue...${c.reset}`);
|
|
112
|
+
console.log(`
|
|
113
|
+
${c.white}${c.bold} STEP 1 OF 4: CHOOSE YOUR EXCHANGE${c.reset}
|
|
114
|
+
${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\u2500\u2500\u2500${c.reset}
|
|
115
|
+
|
|
116
|
+
${c.dim}Popular exchanges:${c.reset}
|
|
117
|
+
|
|
118
|
+
${c.cyan}[1]${c.reset} Binance ${c.dim}Largest exchange, global${c.reset}
|
|
119
|
+
${c.cyan}[2]${c.reset} Coinbase ${c.dim}US-based, beginner friendly${c.reset}
|
|
120
|
+
${c.cyan}[3]${c.reset} Kraken ${c.dim}Security focused, EU/US${c.reset}
|
|
121
|
+
${c.cyan}[4]${c.reset} Bybit ${c.dim}Derivatives, Asia${c.reset}
|
|
122
|
+
${c.cyan}[5]${c.reset} OKX ${c.dim}Full-featured, global${c.reset}
|
|
123
|
+
${c.cyan}[6]${c.reset} KuCoin ${c.dim}Altcoin variety${c.reset}
|
|
124
|
+
${c.cyan}[7]${c.reset} Other ${c.dim}Enter exchange name manually${c.reset}
|
|
125
|
+
|
|
126
|
+
`);
|
|
127
|
+
const exchangeChoice = await question(` ${c.yellow}?${c.reset} Select exchange ${c.dim}[1-7]${c.reset}: `);
|
|
128
|
+
const exchangeMap = {
|
|
129
|
+
"1": "binance",
|
|
130
|
+
"2": "coinbase",
|
|
131
|
+
"3": "kraken",
|
|
132
|
+
"4": "bybit",
|
|
133
|
+
"5": "okx",
|
|
134
|
+
"6": "kucoin"
|
|
135
|
+
};
|
|
136
|
+
let exchange = exchangeMap[exchangeChoice.trim()];
|
|
137
|
+
if (!exchange) {
|
|
138
|
+
exchange = await question(` ${c.yellow}?${c.reset} Enter exchange name: `);
|
|
139
|
+
}
|
|
140
|
+
exchange = exchange.toLowerCase().trim();
|
|
141
|
+
console.log(`
|
|
142
|
+
${c.white}${c.bold} STEP 2 OF 4: GET YOUR API KEYS${c.reset}
|
|
143
|
+
${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\u2500\u2500\u2500${c.reset}
|
|
144
|
+
|
|
145
|
+
${c.dim}You need to create API keys on ${c.white}${exchange}${c.dim}. Here's how:${c.reset}
|
|
146
|
+
`);
|
|
147
|
+
if (exchange === "binance") {
|
|
148
|
+
console.log(`
|
|
149
|
+
${c.cyan}1.${c.reset} Go to ${c.blue}https://testnet.binance.vision/${c.reset} ${c.dim}(for testnet)${c.reset}
|
|
150
|
+
Or ${c.blue}https://www.binance.com/en/my/settings/api-management${c.reset} ${c.dim}(real)${c.reset}
|
|
151
|
+
${c.cyan}2.${c.reset} Click "${c.white}Generate HMAC_SHA256 Key${c.reset}"
|
|
152
|
+
${c.cyan}3.${c.reset} Enable permissions: ${c.green}\u2713 Read${c.reset} ${c.green}\u2713 Trade${c.reset} ${c.red}\u2717 Withdraw${c.reset}
|
|
153
|
+
${c.cyan}4.${c.reset} Copy the ${c.white}API Key${c.reset} and ${c.white}Secret Key${c.reset}
|
|
154
|
+
`);
|
|
155
|
+
} else if (exchange === "coinbase") {
|
|
156
|
+
console.log(`
|
|
157
|
+
${c.cyan}1.${c.reset} Go to ${c.blue}https://portal.cdp.coinbase.com/${c.reset}
|
|
158
|
+
${c.cyan}2.${c.reset} Create a new project
|
|
159
|
+
${c.cyan}3.${c.reset} Generate API credentials
|
|
160
|
+
${c.cyan}4.${c.reset} Copy ${c.white}API Key${c.reset}, ${c.white}Secret${c.reset}, and ${c.white}Passphrase${c.reset}
|
|
161
|
+
`);
|
|
162
|
+
} else if (exchange === "kraken") {
|
|
163
|
+
console.log(`
|
|
164
|
+
${c.cyan}1.${c.reset} Go to ${c.blue}https://www.kraken.com/u/security/api${c.reset}
|
|
165
|
+
${c.cyan}2.${c.reset} Click "Generate new key"
|
|
166
|
+
${c.cyan}3.${c.reset} Enable: ${c.green}\u2713 Query${c.reset} ${c.green}\u2713 Trade${c.reset} ${c.red}\u2717 Withdraw${c.reset}
|
|
167
|
+
${c.cyan}4.${c.reset} Copy the ${c.white}API Key${c.reset} and ${c.white}Private Key${c.reset}
|
|
168
|
+
`);
|
|
169
|
+
} else {
|
|
170
|
+
console.log(`
|
|
171
|
+
${c.cyan}1.${c.reset} Log in to ${c.white}${exchange}${c.reset}
|
|
172
|
+
${c.cyan}2.${c.reset} Go to API settings ${c.dim}(usually in Settings or Security)${c.reset}
|
|
173
|
+
${c.cyan}3.${c.reset} Create a new API key
|
|
174
|
+
${c.cyan}4.${c.reset} Enable: ${c.green}\u2713 Read${c.reset} ${c.green}\u2713 Trade${c.reset} ${c.red}\u2717 Withdraw${c.reset} ${c.dim}(never enable withdraw!)${c.reset}
|
|
175
|
+
${c.cyan}5.${c.reset} Copy the ${c.white}API Key${c.reset} and ${c.white}Secret${c.reset}
|
|
176
|
+
`);
|
|
177
|
+
}
|
|
178
|
+
console.log(`
|
|
179
|
+
${c.orange} \u26A0 SECURITY TIP: Never enable withdrawal permissions!${c.reset}
|
|
180
|
+
`);
|
|
181
|
+
await question(` ${c.dim}Press Enter when you have your API keys ready...${c.reset}`);
|
|
182
|
+
console.log(`
|
|
183
|
+
${c.white}${c.bold} STEP 3 OF 4: ENTER YOUR API KEYS${c.reset}
|
|
184
|
+
${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\u2500\u2500\u2500${c.reset}
|
|
185
|
+
|
|
186
|
+
${c.dim}Your keys are stored locally at ~/.omnitrade/config.json${c.reset}
|
|
187
|
+
${c.dim}They never leave your machine.${c.reset}
|
|
188
|
+
|
|
189
|
+
`);
|
|
190
|
+
const apiKey = await question(` ${c.yellow}?${c.reset} API Key: `);
|
|
191
|
+
const secret = await question(` ${c.yellow}?${c.reset} Secret Key: `);
|
|
192
|
+
let password = "";
|
|
193
|
+
if (["coinbase", "kucoin", "okx"].includes(exchange)) {
|
|
194
|
+
password = await question(` ${c.yellow}?${c.reset} Passphrase ${c.dim}(required for ${exchange})${c.reset}: `);
|
|
195
|
+
}
|
|
196
|
+
const testnetAnswer = await question(` ${c.yellow}?${c.reset} Use testnet/sandbox mode? ${c.dim}(recommended)${c.reset} [Y/n]: `);
|
|
197
|
+
const testnet = testnetAnswer.toLowerCase() !== "n";
|
|
198
|
+
rl.close();
|
|
199
|
+
const config = {
|
|
200
|
+
exchanges: {
|
|
201
|
+
[exchange]: {
|
|
202
|
+
apiKey: apiKey.trim(),
|
|
203
|
+
secret: secret.trim(),
|
|
204
|
+
...password.trim() ? { password: password.trim() } : {},
|
|
205
|
+
testnet
|
|
206
|
+
}
|
|
207
|
+
},
|
|
208
|
+
security: {
|
|
209
|
+
maxOrderSize: 100,
|
|
210
|
+
confirmTrades: true
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
const configDir = join(homedir(), ".omnitrade");
|
|
214
|
+
if (!existsSync(configDir)) {
|
|
215
|
+
mkdirSync(configDir, { recursive: true });
|
|
216
|
+
}
|
|
217
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
218
|
+
try {
|
|
219
|
+
const { chmodSync } = await import("fs");
|
|
220
|
+
chmodSync(CONFIG_PATH, 384);
|
|
221
|
+
} catch {
|
|
222
|
+
}
|
|
223
|
+
console.log(`
|
|
224
|
+
${c.green}${c.bold} \u2713 CONFIGURATION SAVED${c.reset}
|
|
225
|
+
|
|
226
|
+
${c.white}${c.bold} STEP 4 OF 4: CONNECT TO CLAUDE DESKTOP${c.reset}
|
|
227
|
+
${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\u2500\u2500\u2500${c.reset}
|
|
228
|
+
|
|
229
|
+
${c.dim}Add OmniTrade to Claude Desktop:${c.reset}
|
|
230
|
+
|
|
231
|
+
${c.cyan}1.${c.reset} Open this file in a text editor:
|
|
232
|
+
${c.blue}~/Library/Application Support/Claude/claude_desktop_config.json${c.reset}
|
|
233
|
+
|
|
234
|
+
${c.cyan}2.${c.reset} Add this configuration:
|
|
235
|
+
|
|
236
|
+
${c.gray}{
|
|
237
|
+
"mcpServers": {
|
|
238
|
+
"omnitrade": {
|
|
239
|
+
"command": "omnitrade",
|
|
240
|
+
"args": ["start"]
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}${c.reset}
|
|
244
|
+
|
|
245
|
+
${c.cyan}3.${c.reset} Save the file and ${c.white}restart Claude Desktop${c.reset}
|
|
246
|
+
|
|
247
|
+
${c.cyan}4.${c.reset} Start chatting! Try asking:
|
|
248
|
+
${c.dim}"What's my balance on ${exchange}?"${c.reset}
|
|
249
|
+
${c.dim}"Show me the price of Bitcoin"${c.reset}
|
|
250
|
+
${c.dim}"Buy $10 of ETH"${c.reset}
|
|
251
|
+
|
|
252
|
+
${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\u2500\u2500\u2500${c.reset}
|
|
253
|
+
|
|
254
|
+
${c.white}${c.bold} NEXT STEPS${c.reset}
|
|
255
|
+
|
|
256
|
+
${c.cyan}\u2022${c.reset} Test your connection: ${c.yellow}omnitrade test${c.reset}
|
|
257
|
+
${c.cyan}\u2022${c.reset} View your config: ${c.yellow}omnitrade config${c.reset}
|
|
258
|
+
${c.cyan}\u2022${c.reset} Add more exchanges: ${c.yellow}omnitrade setup${c.reset} ${c.dim}(run again)${c.reset}
|
|
259
|
+
${c.cyan}\u2022${c.reset} Get help: ${c.yellow}omnitrade help${c.reset}
|
|
260
|
+
|
|
261
|
+
${c.green}${c.bold} \u2713 Setup complete! You're ready to trade with AI.${c.reset}
|
|
262
|
+
|
|
263
|
+
`);
|
|
84
264
|
}
|
|
85
265
|
async function showExchanges() {
|
|
86
|
-
|
|
266
|
+
printCompactLogo();
|
|
87
267
|
const ccxt = await import("ccxt");
|
|
88
268
|
const exchanges = ccxt.default.exchanges;
|
|
89
|
-
console.log(`${c.
|
|
269
|
+
console.log(`${c.white}${c.bold} SUPPORTED EXCHANGES${c.reset} ${c.dim}(${exchanges.length} total)${c.reset}
|
|
90
270
|
`);
|
|
91
271
|
const tier1 = ["binance", "bybit", "okx", "gate", "kucoin", "bitget", "htx", "mexc", "cryptocom", "bitmex", "woo", "coinex", "bitmart", "bingx"];
|
|
92
|
-
console.log(`${c.green}${c.bright}\u2605 TIER 1 - CERTIFIED${c.reset}`);
|
|
93
|
-
console.log(` ${tier1.filter((e) => exchanges.includes(e)).join(", ")}`);
|
|
94
272
|
const tier2 = ["coinbase", "kraken", "bitstamp", "gemini", "bitfinex", "poloniex", "deribit", "upbit", "bithumb", "bitvavo", "phemex", "ascendex", "lbank"];
|
|
273
|
+
console.log(` ${c.green}\u2605 TIER 1 - CERTIFIED${c.reset}`);
|
|
274
|
+
console.log(` ${c.dim}${tier1.filter((e) => exchanges.includes(e)).join(", ")}${c.reset}`);
|
|
95
275
|
console.log(`
|
|
96
|
-
${c.yellow}
|
|
97
|
-
console.log(` ${tier2.filter((e) => exchanges.includes(e)).join(", ")}`);
|
|
276
|
+
${c.yellow}\u2605 TIER 2 - MAJOR${c.reset}`);
|
|
277
|
+
console.log(` ${c.dim}${tier2.filter((e) => exchanges.includes(e)).join(", ")}${c.reset}`);
|
|
98
278
|
const others = exchanges.filter((e) => !tier1.includes(e) && !tier2.includes(e));
|
|
99
279
|
console.log(`
|
|
100
|
-
${c.
|
|
101
|
-
const cols =
|
|
280
|
+
${c.gray}\u2605 ALL OTHERS (${others.length})${c.reset}`);
|
|
281
|
+
const cols = 8;
|
|
102
282
|
for (let i = 0; i < others.length; i += cols) {
|
|
103
283
|
const row = others.slice(i, i + cols);
|
|
104
|
-
console.log(` ${c.dim}${row.map((e) => e.padEnd(
|
|
284
|
+
console.log(` ${c.dim}${row.map((e) => e.padEnd(12)).join("")}${c.reset}`);
|
|
105
285
|
}
|
|
106
|
-
console.log(
|
|
107
|
-
${c.bright}Total: ${c.cyan}${exchanges.length}${c.reset} exchanges supported
|
|
108
|
-
`);
|
|
286
|
+
console.log("");
|
|
109
287
|
}
|
|
110
288
|
async function showConfig() {
|
|
111
|
-
|
|
112
|
-
console.log(`${c.
|
|
289
|
+
printCompactLogo();
|
|
290
|
+
console.log(`${c.white}${c.bold} CONFIGURATION${c.reset}
|
|
113
291
|
`);
|
|
114
|
-
console.log(
|
|
292
|
+
console.log(` ${c.dim}Location:${c.reset} ${c.blue}${CONFIG_PATH}${c.reset}
|
|
115
293
|
`);
|
|
116
294
|
if (!existsSync(CONFIG_PATH)) {
|
|
117
|
-
console.log(
|
|
295
|
+
console.log(` ${c.red}\u2717 No configuration found${c.reset}`);
|
|
118
296
|
console.log(`
|
|
119
|
-
Run ${c.cyan}omnitrade
|
|
297
|
+
Run ${c.cyan}omnitrade setup${c.reset} to get started.
|
|
120
298
|
`);
|
|
121
299
|
return;
|
|
122
300
|
}
|
|
123
301
|
try {
|
|
124
302
|
const config = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
|
|
125
303
|
const exchanges = Object.keys(config.exchanges || {});
|
|
126
|
-
console.log(
|
|
304
|
+
console.log(` ${c.green}\u2713 Config loaded${c.reset}
|
|
127
305
|
`);
|
|
128
|
-
console.log(
|
|
306
|
+
console.log(` ${c.white}${c.bold}Exchanges:${c.reset}`);
|
|
129
307
|
for (const ex of exchanges) {
|
|
130
308
|
const cfg = config.exchanges[ex];
|
|
131
|
-
const mode = cfg.testnet ? `${c.yellow}testnet${c.reset}` : `${c.green}
|
|
132
|
-
console.log(`
|
|
309
|
+
const mode = cfg.testnet ? `${c.yellow}testnet${c.reset}` : `${c.green}live${c.reset}`;
|
|
310
|
+
console.log(` ${c.cyan}\u2022${c.reset} ${ex} (${mode})`);
|
|
133
311
|
}
|
|
134
312
|
if (config.security) {
|
|
135
313
|
console.log(`
|
|
136
|
-
${c.
|
|
314
|
+
${c.white}${c.bold}Security:${c.reset}`);
|
|
137
315
|
if (config.security.maxOrderSize) {
|
|
138
|
-
console.log(`
|
|
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}`);
|
|
316
|
+
console.log(` ${c.cyan}\u2022${c.reset} Max order: $${config.security.maxOrderSize}`);
|
|
145
317
|
}
|
|
146
318
|
}
|
|
147
319
|
console.log("");
|
|
148
320
|
} catch (error) {
|
|
149
|
-
console.log(
|
|
321
|
+
console.log(` ${c.red}\u2717 Error:${c.reset} ${error.message}
|
|
150
322
|
`);
|
|
151
323
|
}
|
|
152
324
|
}
|
|
153
325
|
async function testConnections() {
|
|
154
|
-
|
|
155
|
-
console.log(`${c.
|
|
326
|
+
printCompactLogo();
|
|
327
|
+
console.log(`${c.white}${c.bold} TESTING CONNECTIONS${c.reset}
|
|
156
328
|
`);
|
|
157
329
|
if (!existsSync(CONFIG_PATH)) {
|
|
158
|
-
console.log(
|
|
330
|
+
console.log(` ${c.red}\u2717 No configuration found${c.reset}`);
|
|
159
331
|
console.log(`
|
|
160
|
-
Run ${c.cyan}omnitrade
|
|
332
|
+
Run ${c.cyan}omnitrade setup${c.reset} to get started.
|
|
161
333
|
`);
|
|
162
334
|
return;
|
|
163
335
|
}
|
|
@@ -194,66 +366,15 @@ async function testConnections() {
|
|
|
194
366
|
}
|
|
195
367
|
console.log("");
|
|
196
368
|
}
|
|
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
369
|
async function main() {
|
|
254
370
|
const args = process.argv.slice(2);
|
|
255
|
-
const command = args[0] || "
|
|
371
|
+
const command = args[0] || "help";
|
|
256
372
|
switch (command) {
|
|
373
|
+
case "setup":
|
|
374
|
+
case "init":
|
|
375
|
+
case "configure":
|
|
376
|
+
await runSetupWizard();
|
|
377
|
+
break;
|
|
257
378
|
case "help":
|
|
258
379
|
case "--help":
|
|
259
380
|
case "-h":
|
|
@@ -262,7 +383,7 @@ async function main() {
|
|
|
262
383
|
case "version":
|
|
263
384
|
case "--version":
|
|
264
385
|
case "-v":
|
|
265
|
-
|
|
386
|
+
console.log(`omnitrade v${VERSION}`);
|
|
266
387
|
break;
|
|
267
388
|
case "exchanges":
|
|
268
389
|
case "list":
|
|
@@ -275,10 +396,6 @@ async function main() {
|
|
|
275
396
|
case "test":
|
|
276
397
|
await testConnections();
|
|
277
398
|
break;
|
|
278
|
-
case "init":
|
|
279
|
-
case "setup":
|
|
280
|
-
await initConfig();
|
|
281
|
-
break;
|
|
282
399
|
case "start":
|
|
283
400
|
case "serve":
|
|
284
401
|
case "run":
|
|
@@ -286,7 +403,7 @@ async function main() {
|
|
|
286
403
|
break;
|
|
287
404
|
default:
|
|
288
405
|
console.log(`${c.red}Unknown command: ${command}${c.reset}`);
|
|
289
|
-
console.log(`Run ${c.cyan}omnitrade
|
|
406
|
+
console.log(`Run ${c.cyan}omnitrade help${c.reset} for usage.
|
|
290
407
|
`);
|
|
291
408
|
process.exit(1);
|
|
292
409
|
}
|
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.0";
|
|
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.0",
|
|
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": {
|