cryptoiz-mcp 2.0.1 → 2.1.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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/index.js +290 -167
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cryptoiz-mcp",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "CryptoIZ MCP Server — Solana DEX signals with x402 micropayments. Pay $0.01 USDC per call.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -1,25 +1,4 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * CryptoIZ MCP Server v2.0.0
4
- * Solana DEX signals with x402 micropayments — $0.01 USDC per call
5
- *
6
- * Setup di Claude Desktop:
7
- * {
8
- * "mcpServers": {
9
- * "cryptoiz": {
10
- * "command": "npx",
11
- * "args": ["cryptoiz-mcp"],
12
- * "env": {
13
- * "SVM_PRIVATE_KEY": "your-solana-private-key-base58"
14
- * }
15
- * }
16
- * }
17
- * }
18
- *
19
- * User harus punya USDC di wallet Solana mereka.
20
- * Setiap call = $0.01 USDC otomatis terkirim ke CryptoIZ.
21
- */
22
-
23
2
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
24
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
25
4
  import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
@@ -32,108 +11,280 @@ const SVM_PRIVATE_KEY = process.env.SVM_PRIVATE_KEY || '';
32
11
  const CRYPTOIZ_WALLET = new PublicKey('DsKmdkYx49Xc1WhqMUAztwhdYPTqieyC98VmnnJdgpXX');
33
12
  const USDC_MINT = new PublicKey('EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v');
34
13
  const SOL_RPC = 'https://api.mainnet-beta.solana.com';
35
- const AMOUNT = 10000; // 0.01 USDC
14
+ const AMOUNT = 10000;
36
15
 
37
- // ─── Payment handler ─────────────────────────────────────────────────────────
16
+ // ─── Footer branding (selalu muncul di setiap response) ──────────────────────
17
+ const FOOTER = `
18
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
19
+ 🌐 cryptoiz.org — Platform AI Trading Solana
20
+ 📊 Alpha Scanner · Divergence · Accumulation · BTC Regime
21
+ 🐦 Twitter/X : @cryptoiz_IDN
22
+ 💬 Telegram : t.me/agus_artemiss
23
+ 💡 Untuk data lebih lengkap, analisis mendalam, dan sinyal premium
24
+ kunjungi cryptoiz.org dan subscribe platform kami.
25
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`;
38
26
 
27
+ // ─── Payment handler ──────────────────────────────────────────────────────────
39
28
  async function payAndFetch(url) {
40
29
  if (!SVM_PRIVATE_KEY) {
41
- return {
42
- error: 'SVM_PRIVATE_KEY tidak ditemukan.',
43
- setup: 'Tambahkan SVM_PRIVATE_KEY (private key Solana kamu) ke config Claude Desktop.',
44
- help: 'cryptoiz.org/McpApiKey',
45
- };
30
+ return { error: 'SVM_PRIVATE_KEY tidak ditemukan.', setup: 'Tambahkan SVM_PRIVATE_KEY ke config Claude Desktop.', help: 'cryptoiz.org' };
46
31
  }
47
-
48
- // First request
49
32
  const first = await fetch(url);
50
33
  if (first.status !== 402) return first.json();
51
-
52
- // 402 received — pay USDC
53
34
  try {
54
35
  const keypair = Keypair.fromSecretKey(bs58.decode(SVM_PRIVATE_KEY));
55
36
  const connection = new Connection(SOL_RPC, 'confirmed');
56
-
57
- const fromAta = await getOrCreateAssociatedTokenAccount(
58
- connection, keypair, USDC_MINT, keypair.publicKey
59
- );
60
- const toAta = await getOrCreateAssociatedTokenAccount(
61
- connection, keypair, USDC_MINT, CRYPTOIZ_WALLET
62
- );
63
-
64
- const tx = new Transaction().add(
65
- createTransferInstruction(fromAta.address, toAta.address, keypair.publicKey, AMOUNT)
66
- );
67
-
37
+ const fromAta = await getOrCreateAssociatedTokenAccount(connection, keypair, USDC_MINT, keypair.publicKey);
38
+ const toAta = await getOrCreateAssociatedTokenAccount(connection, keypair, USDC_MINT, CRYPTOIZ_WALLET);
39
+ const tx = new Transaction().add(createTransferInstruction(fromAta.address, toAta.address, keypair.publicKey, AMOUNT));
68
40
  const signature = await connection.sendTransaction(tx, [keypair]);
69
41
  await connection.confirmTransaction(signature, 'confirmed');
70
-
71
- // Retry with payment proof
72
- const payment = Buffer.from(
73
- JSON.stringify({ signature, network: 'solana', x402Version: 1 })
74
- ).toString('base64');
75
-
42
+ const payment = Buffer.from(JSON.stringify({ signature, network: 'solana', x402Version: 1 })).toString('base64');
76
43
  const paidRes = await fetch(url, { headers: { 'x-payment': payment } });
77
44
  return paidRes.json();
78
-
79
45
  } catch (err) {
80
- return {
81
- error: `Payment gagal: ${err.message}`,
82
- hint: 'Pastikan wallet kamu punya USDC dan SOL untuk gas.',
83
- };
46
+ return { error: `Payment gagal: ${err.message}`, hint: 'Pastikan wallet punya USDC dan SOL untuk gas.' };
84
47
  }
85
48
  }
86
49
 
50
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
51
+ const fmt = (n, d=2) => n != null ? parseFloat(n).toFixed(d) : 'N/A';
52
+ const fmtMC = mc => { if (!mc) return 'N/A'; if (mc >= 1e6) return `$${(mc/1e6).toFixed(2)}M`; return `$${(mc/1000).toFixed(0)}K`; };
53
+ const fmtD = d => d > 0 ? `+${d}` : `${d}`;
54
+ const fmtRisk = r => parseFloat(r) > 0 ? `⚠️ ${fmt(r)}%` : `✅ 0%`;
55
+ const fmtPrice = p => p ? `$${parseFloat(p).toFixed(6)}` : 'N/A';
56
+
57
+ function entryAdvice(s) {
58
+ const lines = [];
59
+ if (s.entry_class === 'ALPHA_EARLY' && s.phase?.includes('ACCUM')) {
60
+ lines.push('💡 SINYAL KUAT: Fase akumulasi awal dengan smart money masuk. Potensi entry terbaik sebelum harga naik.');
61
+ } else if (s.entry_class === 'ALPHA_BUILDING') {
62
+ lines.push('💡 MEMBANGUN: Akumulasi sedang berlanjut. Timing masih baik namun hati-hati dengan risiko.');
63
+ } else {
64
+ lines.push('👁️ WATCHLIST: Belum memenuhi semua kriteria entry. Monitor terus untuk konfirmasi.');
65
+ }
66
+ if (s.whale_delta > 0 && s.dolphin_delta > 0) lines.push('✅ Whale & Dolphin sama-sama masuk — sinyal kuat smart money akumulasi.');
67
+ if (s.smart_money_trap_risk > 30) lines.push('⚠️ Trap Risk tinggi — waspadai jebakan sebelum entry.');
68
+ if (s.liquidity_drain_risk > 30) lines.push('⚠️ Liquidity Risk tinggi — pastikan ada likuiditas cukup saat exit.');
69
+ if (s.safety_score >= 80) lines.push('🛡️ Safety score tinggi — risiko manipulasi rendah.');
70
+ return lines.join('\n ');
71
+ }
72
+
73
+ function divergenceAdvice(s) {
74
+ if (s.divergence_type === 'bullish') return '💡 BULLISH DIVERGENCE: Harga turun tapi whale/dolphin masuk. Potensi reversal ke atas — perhatikan untuk entry.';
75
+ if (s.divergence_type === 'bearish') return '⚠️ BEARISH DIVERGENCE: Harga naik tapi whale/dolphin keluar. Potensi reversal ke bawah — hati-hati jika sudah hold.';
76
+ return '📊 Divergence terdeteksi — analisa lebih lanjut diperlukan.';
77
+ }
78
+
79
+ function accumAdvice(s) {
80
+ if (s.strength_label?.includes('VERY_STRONG')) return '💡 VERY STRONG: Smart money sangat aktif akumulasi. Kandidat entry terkuat.';
81
+ if (s.strength_label?.includes('STRONG')) return '💡 STRONG: Akumulasi kuat terdeteksi. Perhatikan untuk entry opportunity.';
82
+ return '👁️ FORMING: Akumulasi mulai terbentuk. Monitor untuk konfirmasi lebih lanjut.';
83
+ }
84
+
87
85
  // ─── Formatters ───────────────────────────────────────────────────────────────
88
86
 
89
87
  function formatAlpha(data) {
90
- if (data.error) return `ERROR: ${data.error}\n${data.setup || ''}`;
91
- if (!data.signals?.length) return 'Tidak ada sinyal Alpha Scanner saat ini.';
88
+ if (data.error) return `❌ ${data.error}\n${data.setup||''}\n📱 Setup: cryptoiz.org`;
89
+ if (!data.signals?.length) return `Tidak ada sinyal Alpha Scanner saat ini.\n${FOOTER}`;
90
+
92
91
  const lines = [
93
- `CRYPTOIZ ALPHA SCANNER | ${data.fetched_at?.split('T')[0]}`,
94
- `Total: ${data.total} sinyal | Powered by cryptoiz.org`,
95
- '',
96
- ...data.signals.map((s, i) => {
97
- const mc = s.market_cap ? `MC: $${(s.market_cap/1000).toFixed(0)}K` : '';
98
- const price = s.price_usd ? `Price: $${parseFloat(s.price_usd).toFixed(6)}` : '';
99
- const addr = s.token_address ? `\n Address: ${s.token_address}` : '';
100
- return `${i+1}. ${s.name} Score: ${s.alpha_score} | ${s.entry_class}\n Phase: ${s.phase_label} | Whale: ${s.whale_delta > 0 ? '+' : ''}${s.whale_delta} | Dolphin: ${s.dolphin_delta > 0 ? '+' : ''}${s.dolphin_delta} | ${mc} | ${price}${addr}`;
101
- }),
102
- '',
103
- '📊 cryptoiz.org | @cryptoiz_IDN',
92
+ `╔══════════════════════════════════════╗`,
93
+ `║ CRYPTOIZ ALPHA ENTRY SCANNER ║`,
94
+ `╚══════════════════════════════════════╝`,
95
+ `📅 ${data.fetched_at?.split('T')[0]} | Total Sinyal: ${data.total}`,
96
+ ``,
97
+ `📖 APA INI?`,
98
+ `Alpha Scanner menggunakan AI untuk mendeteksi token Solana`,
99
+ `yang sedang diakumulasi oleh whale & dolphin (smart money)`,
100
+ `sebelum harga bergerak. Score 0-100 berdasarkan:`,
101
+ `• Accumulation Score — seberapa aktif smart money masuk`,
102
+ `• Timing Score — seberapa tepat timing entry`,
103
+ `• Safety Score — seberapa aman dari manipulasi`,
104
+ ``,
105
+ `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
106
+ ...data.signals.map((s, i) => [
107
+ ``,
108
+ `${i+1}. ━━━ ${s.name} ━━━━━━━━━━━━━━━━━━━`,
109
+ ` 🔗 Address : ${s.token_address}`,
110
+ ` 📊 Alpha Score: ${fmt(s.alpha_score)} / 100 | Kelas: ${s.entry_class}`,
111
+ ` 📍 Phase : ${s.phase} | Regime: ${s.regime}`,
112
+ ` 🎯 Keyakinan : ${fmt(s.phase_confidence)}% | Umur Phase: ${s.phase_age_bars} bars`,
113
+ ``,
114
+ ` HOLDER SIGNALS:`,
115
+ ` 🐋 Whale : ${fmtD(s.whale_delta)} (${fmt(s.whale_pct)}% supply)`,
116
+ ` 🐬 Dolphin : ${fmtD(s.dolphin_delta)} (${fmt(s.dolphin_pct)}% supply)`,
117
+ ` 🦐 Shrimp : ${fmtD(s.shrimp_delta)} (keluar = bullish)`,
118
+ ``,
119
+ ` SUB-SCORES:`,
120
+ ` 📈 Accum : ${fmt(s.accumulation_score)} | Timing: ${fmt(s.timing_score)} | Safety: ${fmt(s.safety_score)}`,
121
+ ``,
122
+ ` RISIKO:`,
123
+ ` 💧 Liquidity : ${fmtRisk(s.liquidity_drain_risk)}`,
124
+ ` 🪤 Trap Risk : ${fmtRisk(s.smart_money_trap_risk)}`,
125
+ ``,
126
+ ` MARKET DATA:`,
127
+ ` 💰 Market Cap : ${fmtMC(s.market_cap_usd)}`,
128
+ ` 💵 Price : ${fmtPrice(s.price_usd)}`,
129
+ ` 📉 Drop Peak : ${s.price_drop_pct != null ? fmt(s.price_drop_pct)+'%' : 'N/A'}`,
130
+ ``,
131
+ ` REKOMENDASI:`,
132
+ ` ${entryAdvice(s)}`,
133
+ `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
134
+ ].join('\n')),
135
+ FOOTER,
104
136
  ];
105
137
  return lines.join('\n');
106
138
  }
107
139
 
108
140
  function formatDivergence(data) {
109
- if (data.error) return `ERROR: ${data.error}\n${data.hint || ''}`;
110
- if (!data.signals?.length) return `Tidak ada divergence signal (${data.timeframe}).`;
141
+ if (data.error) return `❌ ${data.error}\n${FOOTER}`;
142
+ if (!data.signals?.length) return `Tidak ada divergence signal (${data.timeframe}).\n${FOOTER}`;
143
+
111
144
  const lines = [
112
- `CRYPTOIZ DIVERGENCE — ${data.timeframe?.toUpperCase()}`,
113
- `Total: ${data.total} | Powered by cryptoiz.org`,
114
- '',
145
+ `╔══════════════════════════════════════╗`,
146
+ `║ CRYPTOIZ DIVERGENCE SCANNER ║`,
147
+ `╚══════════════════════════════════════╝`,
148
+ `📅 ${data.fetched_at?.split('T')[0]} | Timeframe: ${data.timeframe?.toUpperCase()} | Total: ${data.total}`,
149
+ ``,
150
+ `📖 APA INI?`,
151
+ `Divergence terjadi ketika harga bergerak berlawanan dengan`,
152
+ `aktivitas smart money (whale/dolphin). Ini adalah sinyal awal`,
153
+ `sebelum harga berbalik arah:`,
154
+ `• BULLISH: Harga turun tapi smart money masuk → potensi naik`,
155
+ `• BEARISH: Harga naik tapi smart money keluar → potensi turun`,
156
+ ``,
157
+ `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
115
158
  ...data.signals.map((s, i) => {
116
- const type = s.divergence_type === 'bullish' ? 'BULLISH 🟢' : s.divergence_type === 'bearish' ? 'BEARISH 🔴' : (s.divergence_type||'').toUpperCase();
117
- return `${i+1}. ${s.name||s.symbol} [${type}]\n Score: ${s.divergence_score?.toFixed(1)||'-'} | MC: $${((s.market_cap||0)/1000).toFixed(0)}K`;
159
+ const type = s.divergence_type === 'bullish' ? '🟢 BULLISH' : s.divergence_type === 'bearish' ? '🔴 BEARISH' : `⚪ ${(s.divergence_type||'').toUpperCase()}`;
160
+ return [
161
+ ``,
162
+ `${i+1}. ━━━ ${s.name||s.symbol} [${type}] ━━━`,
163
+ ` 🔗 Address : ${s.token_address}`,
164
+ ` 📊 Div. Score : ${fmt(s.divergence_score)} | Confidence: ${fmt(s.confidence_score)}%`,
165
+ ` 📍 Phase : ${s.phase_label}`,
166
+ ``,
167
+ ` HOLDER SIGNALS:`,
168
+ ` 🐋 Whale : ${fmtD(s.whale_delta)}`,
169
+ ` 🐬 Dolphin : ${fmtD(s.dolphin_delta)}`,
170
+ ``,
171
+ ` MARKET DATA:`,
172
+ ` 💰 Market Cap : ${fmtMC(s.market_cap_usd)}`,
173
+ ` 💵 Price Now : ${fmtPrice(s.price_usd)}`,
174
+ ` 📉 Price Chg : ${s.price_change_pct ? fmt(s.price_change_pct)+'%' : 'N/A'}`,
175
+ ` 🕐 Detected : ${s.detected_at ? new Date(s.detected_at).toLocaleString('id-ID') : 'N/A'}`,
176
+ ``,
177
+ ` REKOMENDASI:`,
178
+ ` ${divergenceAdvice(s)}`,
179
+ `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
180
+ ].join('\n');
118
181
  }),
119
- '',
120
- '📊 cryptoiz.org | @cryptoiz_IDN',
182
+ FOOTER,
183
+ ];
184
+ return lines.join('\n');
185
+ }
186
+
187
+ function formatAccumulation(data) {
188
+ if (data.error) return `❌ ${data.error}\n${FOOTER}`;
189
+ if (!data.tokens?.length) return `Tidak ada token dalam fase akumulasi.\n${FOOTER}`;
190
+
191
+ const lines = [
192
+ `╔══════════════════════════════════════╗`,
193
+ `║ CRYPTOIZ ACCUMULATION SCANNER ║`,
194
+ `╚══════════════════════════════════════╝`,
195
+ `📅 ${data.fetched_at?.split('T')[0]} | Total: ${data.total} token akumulasi`,
196
+ ``,
197
+ `📖 APA INI?`,
198
+ `Accumulation Dashboard mendeteksi token yang sedang dalam`,
199
+ `fase akumulasi berdasarkan 4 dimensi analisis:`,
200
+ `• Structure Score — pola price action & holder tier`,
201
+ `• AccDist Score — distribusi akumulasi vs distribusi`,
202
+ `• Holder Score — kualitas & konsistensi holder`,
203
+ `• Market Score — kondisi pasar & volume`,
204
+ `Composite Score = gabungan keempat dimensi di atas.`,
205
+ ``,
206
+ `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
207
+ ...data.tokens.map((t, i) => [
208
+ ``,
209
+ `${i+1}. ━━━ ${t.name} ━━━━━━━━━━━━━━━━━━━`,
210
+ ` 🔗 Address : ${t.token_address}`,
211
+ ` 📊 Composite : ${fmt(t.composite_score)} / 100`,
212
+ ` 💪 Strength : ${t.strength_label}`,
213
+ ` 🔄 AccDist : ${t.accdist_label} (Score: ${fmt(t.accdist_score)})`,
214
+ ``,
215
+ ` SUB-SCORES:`,
216
+ ` 📐 Structure : ${fmt(t.structure_score)}`,
217
+ ` 👥 Holder : ${fmt(t.holder_score)}`,
218
+ ` 📉 Market : ${fmt(t.market_score)}`,
219
+ ``,
220
+ ` REKOMENDASI:`,
221
+ ` ${accumAdvice(t)}`,
222
+ `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
223
+ ].join('\n')),
224
+ FOOTER,
121
225
  ];
122
226
  return lines.join('\n');
123
227
  }
124
228
 
125
- function formatAccum(data) {
126
- if (data.error) return `ERROR: ${data.error}\n${data.hint || ''}`;
127
- if (!data.tokens?.length) return 'Tidak ada token dalam fase akumulasi.';
229
+ function formatBTC(data) {
230
+ if (data.error) return `❌ ${data.error}\n${FOOTER}`;
231
+ const s = data.btc_signal || {};
232
+ const f = data.futures_signal || {};
233
+ const ind = data.indicators || {};
234
+
235
+ const stateEmoji = s.state === 'bull' ? '🟢' : s.state === 'bear' ? '🔴' : '🟡';
236
+ const signalEmoji = f.signal === 'LONG' ? '🟢' : f.signal === 'SHORT' ? '🔴' : '🟡';
237
+
128
238
  const lines = [
129
- `CRYPTOIZ AKUMULASI`,
130
- `Total: ${data.total} | Powered by cryptoiz.org`,
131
- '',
132
- ...data.tokens.map((t, i) =>
133
- `${i+1}. ${t.name} — Composite: ${t.composite_score?.toFixed(1)||'N/A'} | ${t.strength_label}\n AccDist: ${t.accdist_score?.toFixed(0)||'-'} | Holder: ${t.holder_score?.toFixed(1)||'-'} | Market: ${t.market_score?.toFixed(1)||'-'}`
134
- ),
135
- '',
136
- '📊 cryptoiz.org | @cryptoiz_IDN',
239
+ `╔══════════════════════════════════════╗`,
240
+ `║ CRYPTOIZ BTC REGIME MONITOR ║`,
241
+ `╚══════════════════════════════════════╝`,
242
+ `📅 ${data.fetched_at?.split('T')[0]}`,
243
+ ``,
244
+ `📖 APA INI?`,
245
+ `BTC Regime Monitor menganalisis kondisi makro Bitcoin`,
246
+ `untuk membantu kamu memahami apakah pasar sedang bullish,`,
247
+ `bearish, atau neutral. Ini penting karena kondisi BTC`,
248
+ `sangat mempengaruhi pergerakan altcoin di Solana.`,
249
+ ``,
250
+ `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
251
+ ``,
252
+ `${stateEmoji} KONDISI BTC SAAT INI: ${(s.state||'').toUpperCase()}`,
253
+ ` 💵 Harga BTC : $${s.last_price ? parseFloat(s.last_price).toLocaleString() : 'N/A'}`,
254
+ ` 📊 BTC Score : ${s.score || 'N/A'} (0=sangat bear, 10=sangat bull)`,
255
+ ` 📈 Trend : ${s.trend || 'N/A'}`,
256
+ ``,
257
+ `SENTIMENT:`,
258
+ ` 😱 Fear & Greed: ${s.fear_label || 'N/A'} (${s.fear_value || 'N/A'}/100)`,
259
+ ` 💡 ${s.fear_value <= 25 ? 'Extreme Fear = peluang beli sering muncul di level ini' : s.fear_value >= 75 ? 'Extreme Greed = hati-hati, pasar bisa reversal' : 'Sentimen netral — ikuti sinyal teknikal'}`,
260
+ ``,
261
+ `FUTURES DATA:`,
262
+ ` ${signalEmoji} Signal Futures : ${f.signal || 'N/A'}`,
263
+ ` 📊 OI Regime : ${f.oi_regime || 'N/A'}`,
264
+ ` 💸 Funding : ${f.funding_regime || 'N/A'}`,
265
+ ` 💵 Perp Price : $${f.perp_price ? parseFloat(f.perp_price).toLocaleString() : 'N/A'}`,
266
+ ` 📝 Alasan : ${f.reason || 'N/A'}`,
267
+ ``,
268
+ ind.rsi ? [
269
+ `INDIKATOR TEKNIKAL (1H):`,
270
+ ` RSI : ${fmt(ind.rsi)} ${parseFloat(ind.rsi) < 30 ? '(Oversold ✅)' : parseFloat(ind.rsi) > 70 ? '(Overbought ⚠️)' : '(Normal)'}`,
271
+ ` EMA 20 : $${ind.ema_20 ? parseFloat(ind.ema_20).toLocaleString() : 'N/A'}`,
272
+ ` EMA 50 : $${ind.ema_50 ? parseFloat(ind.ema_50).toLocaleString() : 'N/A'}`,
273
+ ` MACD : ${fmt(ind.macd)} | Signal: ${fmt(ind.macd_signal)}`,
274
+ ``,
275
+ ].join('\n') : '',
276
+ `REKOMENDASI UNTUK ALTCOIN SOLANA:`,
277
+ s.state === 'bull' ? ` 🟢 BTC bullish → kondisi BAGUS untuk cari entry altcoin Solana.
278
+ Fokus pada token dengan Alpha Score tinggi di cryptoiz.org.` :
279
+ s.state === 'bear' ? ` 🔴 BTC bearish → HATI-HATI entry altcoin.
280
+ Prioritaskan token dengan Safety Score tinggi dan liq risk rendah.` :
281
+ ` 🟡 BTC neutral → Selektif dalam memilih entry.
282
+ Tunggu konfirmasi signal sebelum masuk posisi besar.`,
283
+ ` 📊 Cek kondisi terkini di: cryptoiz.org/BTC`,
284
+ ``,
285
+ `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━`,
286
+ `⚠️ Bukan financial advice. Selalu DYOR.`,
287
+ FOOTER,
137
288
  ];
138
289
  return lines.join('\n');
139
290
  }
@@ -141,112 +292,84 @@ function formatAccum(data) {
141
292
  function formatStatus() {
142
293
  const hasKey = !!SVM_PRIVATE_KEY;
143
294
  return [
144
- `CryptoIZ MCP Server v2.0.0`,
145
- `Status : CONNECTED`,
146
- `Payment : ${hasKey ? 'READY — x402 Solana USDC ($0.01/call)' : 'NOT SET — tambahkan SVM_PRIVATE_KEY'}`,
295
+ `╔══════════════════════════════════════╗`,
296
+ `║ CryptoIZ MCP Server v2.1.0 ║`,
297
+ `╚══════════════════════════════════════╝`,
147
298
  ``,
148
- `Tools tersedia:`,
149
- ` 1. get_alpha_scanner — Alpha entry signals terkuat`,
150
- ` 2. get_divergence Divergence bullish/bearish`,
151
- ` 3. get_accumulation — Token fase akumulasi`,
152
- ` 4. get_status — Info ini`,
299
+ `STATUS KONEKSI:`,
300
+ ` CONNECTED ke CryptoIZ Data Engine`,
301
+ ` ${hasKey ? '✅ PAYMENT READY x402 Solana USDC' : '❌ PAYMENT NOT SET — tambahkan SVM_PRIVATE_KEY'}`,
302
+ ` 💰 Harga : $0.01 USDC per call`,
303
+ ` 🏦 Wallet CRZ : DsKmdkYx49Xc1WhqMUAztwhdYPTqieyC98VmnnJdgpXX`,
153
304
  ``,
154
- `Harga : $0.01 USDC per call (Solana)`,
155
- `Wallet : DsKmdkYx49Xc1WhqMUAztwhdYPTqieyC98VmnnJdgpXX`,
156
- `Info : cryptoiz.org | @cryptoiz_IDN`,
305
+ `TOOLS TERSEDIA:`,
306
+ ` 1. get_alpha_scanner — Token Solana dengan akumulasi terkuat`,
307
+ ` Termasuk: address, MC, price, holder signals, sub-scores, risks`,
308
+ ``,
309
+ ` 2. get_divergence — Divergence bullish/bearish`,
310
+ ` Termasuk: address, MC, price, confidence, waktu deteksi`,
311
+ ``,
312
+ ` 3. get_accumulation — Token fase akumulasi (composite score)`,
313
+ ` Termasuk: address, 4 sub-scores, strength label`,
314
+ ``,
315
+ ` 4. get_btc_regime — Kondisi makro Bitcoin`,
316
+ ` Termasuk: price, fear & greed, OI regime, funding, indikator`,
317
+ ``,
318
+ ` 5. get_status — Info server ini`,
319
+ ``,
320
+ `CARA PAKAI:`,
321
+ ` • Tanya: "Sinyal Solana hari ini?"`,
322
+ ` • Tanya: "Ada divergence bullish?"`,
323
+ ` • Tanya: "Token mana yang diakumulasi whale?"`,
324
+ ` • Tanya: "Kondisi BTC sekarang?"`,
325
+ FOOTER,
157
326
  ].join('\n');
158
327
  }
159
328
 
160
- // ─── Tools definition ─────────────────────────────────────────────────────────
161
-
329
+ // ─── Tool definitions ─────────────────────────────────────────────────────────
162
330
  const TOOLS = [
163
- {
164
- name: 'get_alpha_scanner',
165
- description: 'Ambil sinyal token Solana terkuat hari ini dari CryptoIZ Alpha Scanner. Biaya: $0.01 USDC per call via Solana.',
166
- inputSchema: {
167
- type: 'object',
168
- properties: {
169
- min_score: { type: 'number', description: 'Minimum alpha score (0-100).' },
170
- },
171
- required: [],
172
- },
173
- },
174
- {
175
- name: 'get_divergence',
176
- description: 'Ambil divergence signals dari CryptoIZ — deteksi bullish/bearish divergence whale/dolphin di Solana. Biaya: $0.01 USDC.',
177
- inputSchema: {
178
- type: 'object',
179
- properties: {
180
- timeframe: { type: 'string', enum: ['4h', '1d'], description: 'Timeframe. Default: 4h.' },
181
- limit: { type: 'number', description: 'Max results (1-50). Default: 20.' },
182
- },
183
- required: [],
184
- },
185
- },
186
- {
187
- name: 'get_accumulation',
188
- description: 'Ambil token dalam fase akumulasi dari CryptoIZ Accumulation Dashboard. Biaya: $0.01 USDC.',
189
- inputSchema: {
190
- type: 'object',
191
- properties: {
192
- min_composite: { type: 'number', description: 'Minimum composite score (0-100).' },
193
- },
194
- required: [],
195
- },
196
- },
197
- {
198
- name: 'get_status',
199
- description: 'Cek status koneksi CryptoIZ MCP, payment setup, dan tools yang tersedia.',
200
- inputSchema: { type: 'object', properties: {}, required: [] },
201
- },
331
+ { name: 'get_alpha_scanner', description: 'Ambil sinyal token Solana terkuat dari CryptoIZ Alpha Scanner. Termasuk contract address, market cap, price, holder signals (whale/dolphin/shrimp), sub-scores (accum/timing/safety), dan risiko. Biaya $0.01 USDC via Solana.', inputSchema: { type: 'object', properties: { min_score: { type: 'number', description: 'Minimum alpha score (0-100).' }, entry_class: { type: 'string', enum: ['ALPHA_EARLY','ALPHA_BUILDING','WATCHLIST_ONLY'], description: 'Filter entry class.' } }, required: [] } },
332
+ { name: 'get_divergence', description: 'Ambil divergence signals dari CryptoIZ — deteksi bullish/bearish divergence antara harga dan aktivitas whale/dolphin. Termasuk address, MC, price, confidence score, waktu deteksi. Biaya $0.01 USDC.', inputSchema: { type: 'object', properties: { timeframe: { type: 'string', enum: ['4h','1d'], description: 'Timeframe. Default: 4h.' }, limit: { type: 'number', description: 'Max hasil (1-50). Default: 20.' } }, required: [] } },
333
+ { name: 'get_accumulation', description: 'Ambil token dalam fase akumulasi dari CryptoIZ Accumulation Dashboard. Composite score dari 4 dimensi: Structure, AccDist, Holder, Market. Termasuk address. Biaya $0.01 USDC.', inputSchema: { type: 'object', properties: { min_composite: { type: 'number', description: 'Minimum composite score (0-100).' } }, required: [] } },
334
+ { name: 'get_btc_regime', description: 'Ambil kondisi makro Bitcoin dari CryptoIZ BTC Monitor. Termasuk: state (bull/bear/neutral), Fear & Greed Index, OI regime, funding rate, sinyal futures, dan indikator teknikal. Penting untuk konteks altcoin Solana. Biaya $0.01 USDC.', inputSchema: { type: 'object', properties: {}, required: [] } },
335
+ { name: 'get_status', description: 'Cek status koneksi CryptoIZ MCP, info payment, dan daftar tools tersedia.', inputSchema: { type: 'object', properties: {}, required: [] } },
202
336
  ];
203
337
 
204
338
  // ─── Server ───────────────────────────────────────────────────────────────────
205
-
206
- const server = new Server(
207
- { name: 'cryptoiz-mcp', version: '2.0.1' },
208
- { capabilities: { tools: {} } }
209
- );
210
-
339
+ const server = new Server({ name: 'cryptoiz-mcp', version: '2.1.0' }, { capabilities: { tools: {} } });
211
340
  server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
212
-
213
341
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
214
342
  const { name, arguments: args } = request.params;
215
-
216
343
  try {
217
- if (name === 'get_status') {
218
- return { content: [{ type: 'text', text: formatStatus() }] };
219
- }
344
+ if (name === 'get_status') return { content: [{ type: 'text', text: formatStatus() }] };
220
345
 
221
346
  if (name === 'get_alpha_scanner') {
222
- const url = `${GATEWAY_URL}?tool=get_alpha_scanner`;
223
- const data = await payAndFetch(url);
224
- if (args?.min_score && data.signals) {
225
- data.signals = data.signals.filter(s => s.alpha_score >= args.min_score);
226
- data.total = data.signals.length;
227
- }
347
+ const data = await payAndFetch(`${GATEWAY_URL}?tool=get_alpha_scanner`);
348
+ if (args?.min_score && data.signals) { data.signals = data.signals.filter(s => s.alpha_score >= args.min_score); data.total = data.signals.length; }
349
+ if (args?.entry_class && data.signals) { data.signals = data.signals.filter(s => s.entry_class === args.entry_class); data.total = data.signals.length; }
228
350
  return { content: [{ type: 'text', text: formatAlpha(data) }] };
229
351
  }
230
352
 
231
353
  if (name === 'get_divergence') {
232
- const params = new URLSearchParams({ tool: 'get_divergence' });
233
- if (args?.timeframe) params.set('tf', args.timeframe);
234
- if (args?.limit) params.set('limit', String(args.limit));
235
- const data = await payAndFetch(`${GATEWAY_URL}?${params}`);
354
+ const p = new URLSearchParams({ tool: 'get_divergence' });
355
+ if (args?.timeframe) p.set('tf', args.timeframe);
356
+ if (args?.limit) p.set('limit', String(args.limit));
357
+ const data = await payAndFetch(`${GATEWAY_URL}?${p}`);
236
358
  return { content: [{ type: 'text', text: formatDivergence(data) }] };
237
359
  }
238
360
 
239
361
  if (name === 'get_accumulation') {
240
362
  const data = await payAndFetch(`${GATEWAY_URL}?tool=get_accumulation`);
241
- if (args?.min_composite && data.tokens) {
242
- data.tokens = data.tokens.filter(t => t.composite_score >= args.min_composite);
243
- data.total = data.tokens.length;
244
- }
245
- return { content: [{ type: 'text', text: formatAccum(data) }] };
363
+ if (args?.min_composite && data.tokens) { data.tokens = data.tokens.filter(t => t.composite_score >= args.min_composite); data.total = data.tokens.length; }
364
+ return { content: [{ type: 'text', text: formatAccumulation(data) }] };
246
365
  }
247
366
 
248
- return { content: [{ type: 'text', text: `Tool tidak dikenal: ${name}` }], isError: true };
367
+ if (name === 'get_btc_regime') {
368
+ const data = await payAndFetch(`${GATEWAY_URL}?tool=get_btc_regime`);
369
+ return { content: [{ type: 'text', text: formatBTC(data) }] };
370
+ }
249
371
 
372
+ return { content: [{ type: 'text', text: `Tool tidak dikenal: ${name}` }], isError: true };
250
373
  } catch (err) {
251
374
  return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
252
375
  }