cryptoiz-mcp 4.16.15 → 4.16.17

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 (5) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +145 -145
  3. package/index.js +309 -309
  4. package/package.json +50 -49
  5. package/setup.js +51 -51
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 CryptoIZ (https://cryptoiz.org)
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CryptoIZ (https://cryptoiz.org)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,145 +1,145 @@
1
- # cryptoiz-mcp
2
-
3
- [![npm version](https://img.shields.io/npm/v/cryptoiz-mcp.svg)](https://www.npmjs.com/package/cryptoiz-mcp)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
- [![x402scan](https://img.shields.io/badge/x402scan-listed-blue)](https://x402scan.com/server/cbd8fff5-d636-4331-b22b-3291717a4e9e)
6
- [![MCP Marketplace](https://img.shields.io/badge/MCP_Marketplace-listed-green)](https://mcp-marketplace.io/server/io-github-dadang11-cryptoiz)
7
-
8
- **CryptoIZ MCP Server** — Solana DEX whale intelligence as a Model Context Protocol (MCP) server. 9 tools (7 paid + 2 free) for Claude Desktop, Cursor, Codex, and any agentcash-compatible client. Native Solana via x402 V2 + Dexter facilitator (gas-sponsored — no SOL needed, only USDC).
9
-
10
- ## ⚡ Recommended Install (1 line)
11
-
12
- ```bash
13
- npx agentcash add https://mcp.cryptoiz.org
14
- ```
15
-
16
- That's it. agentcash auto-generates a Solana wallet at `~/.agentcash/wallet.json` (no private key in your Claude config). Fund with $1-5 USDC via `npx agentcash fund` and you're ready.
17
-
18
- **Why agentcash:**
19
- - ✅ No private key in Claude Desktop config
20
- - ✅ Wallet auto-generated and isolated
21
- - ✅ Gas sponsored by Dexter (zero SOL needed)
22
- - ✅ Update tools without reinstalling client
23
- - ✅ One wallet across ALL x402 services (CryptoIZ, HYRE, etc.)
24
-
25
- ## 5 Specialized Sub-Agents
26
-
27
- Pick what you need:
28
-
29
- ```bash
30
- npx agentcash add https://mcp.cryptoiz.org/agents/alpha # Whale alpha signals only
31
- npx agentcash add https://mcp.cryptoiz.org/agents/btc # BTC regime + futures
32
- npx agentcash add https://mcp.cryptoiz.org/agents/phases # Accumulation/Neutral/Distribution
33
- npx agentcash add https://mcp.cryptoiz.org/agents/divergence # Divergence patterns
34
- npx agentcash add https://mcp.cryptoiz.org/agents/deep-research # Token deep-dive combo
35
- ```
36
-
37
- ## Tools & Pricing
38
-
39
- | Tool | Cost | Description |
40
- |---|---|---|
41
- | `get_whale_alpha` | $0.05 USDC | Top 20 alpha signals — whale/dolphin accumulation, entry timing |
42
- | `get_whale_divergence` | $0.02 USDC | Hidden/breakout/classic divergence signals (4h/1d) |
43
- | `get_whale_accumulation` | $0.02 USDC | Tokens with smart money accumulating |
44
- | `get_whale_neutral` | $0.02 USDC | Tokens in transition phase |
45
- | `get_whale_distribution` | $0.02 USDC | Tokens with whales selling (exit signal) |
46
- | `get_btc_regime` | $0.01 USDC | BTC macro regime + sentiment + technicals |
47
- | `get_btc_futures_signal` | $0.03 USDC | BTC futures multi-timeframe signal (54% WR) |
48
- | `get_token_ca` | FREE | Look up Solana contract address by name |
49
- | `get_status` | FREE | Server status, available tools, pricing |
50
-
51
- All payments settle on Solana mainnet via [Dexter facilitator](https://x402.dexter.cash). Recipient: `DsKmdkYx49Xc1WhqMUAztwhdYPTqieyC98VmnnJdgpXX`.
52
-
53
- ## Legacy Setup (Advanced — not recommended)
54
-
55
- For users who prefer self-custody with their own Solana wallet:
56
-
57
- ### 1. Install the package globally
58
-
59
- ```bash
60
- npm install -g cryptoiz-mcp
61
- ```
62
-
63
- ### 2. Get a Solana wallet private key (base58)
64
-
65
- You need a Solana wallet with at least **$1 USDC** on mainnet. **No SOL needed** — Dexter sponsors all gas. Recommended: dedicated wallet, NOT your main wallet. Phantom: Settings > Security > Export Private Key.
66
-
67
- ### 3. Edit Claude Desktop config
68
-
69
- File: `%APPDATA%\Claude\claude_desktop_config.json` (Windows) or `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS).
70
-
71
- ```json
72
- {
73
- "mcpServers": {
74
- "cryptoiz": {
75
- "command": "C:\\Program Files\\nodejs\\node.exe",
76
- "args": ["C:\\Users\\<YOU>\\AppData\\Roaming\\npm\\node_modules\\cryptoiz-mcp\\index.js"],
77
- "env": {
78
- "SVM_PRIVATE_KEY": "<your_base58_solana_private_key>"
79
- }
80
- }
81
- }
82
- }
83
- ```
84
-
85
- ### 4. Restart Claude Desktop
86
-
87
- Then ask Claude: `get cryptoiz status` — you should see version `v4.16.14` and the tool list.
88
-
89
- ## Security
90
-
91
- - **agentcash flow** (recommended): private key auto-generated and isolated, never in Claude config
92
- - **Gas-sponsored**: Dexter facilitator pays all gas (you only pay USDC)
93
- - **Server-side validation**: every payment verified via Dexter `/settle` before serving data
94
- - **x402 V2 spec compliant**: open standard, no custom protocol
95
- - **No tracking**: only on-chain transaction signature is recorded for replay protection
96
- - **Dedicated wallet recommended** for legacy npm install (don't use your main wallet)
97
-
98
- ## Listed at
99
-
100
- - [MCP Marketplace](https://mcp-marketplace.io/server/io-github-dadang11-cryptoiz)
101
- - [x402scan](https://x402scan.com/server/cbd8fff5-d636-4331-b22b-3291717a4e9e) — 94+ tx, $2.80+ volume
102
- - [Official MCP Registry](https://github.com/modelcontextprotocol/registry)
103
- - MPPscan (pending)
104
-
105
- ## Architecture
106
-
107
- ```
108
- Claude Desktop / Cursor / Codex
109
- │ (MCP)
110
-
111
- agentcash CLI (or cryptoiz-mcp legacy npm)
112
- │ (HTTP)
113
-
114
- mcp.cryptoiz.org gateway (Cloudflare Worker + Supabase Edge Function)
115
- │ (POST /settle)
116
-
117
- Dexter facilitator (x402.dexter.cash)
118
- │ (signs + broadcasts)
119
-
120
- Solana mainnet
121
- ```
122
-
123
- ## Troubleshooting
124
-
125
- ### "Transaction simulation failed"
126
- Update to latest: `npx agentcash add https://mcp.cryptoiz.org` (or `npm install -g cryptoiz-mcp@latest` for legacy).
127
-
128
- ### "Server disconnected" on Windows
129
- Use absolute paths in Claude config (legacy npm only). agentcash flow doesn't have this issue.
130
-
131
- ### Update notifications keep showing
132
- Run `npm install -g cryptoiz-mcp@latest`, force-kill all `node.exe` processes via Task Manager, then restart Claude Desktop. Or switch to agentcash for auto-updates.
133
-
134
- ## Links
135
-
136
- - **Platform**: https://cryptoiz.org
137
- - **Setup guide**: https://cryptoiz.org/McpLanding
138
- - **Twitter**: [@cryptoiz_IDN](https://twitter.com/cryptoiz_IDN)
139
- - **Telegram**: https://t.me/agus_artemiss
140
- - **MCP Marketplace**: https://mcp-marketplace.io/server/io-github-dadang11-cryptoiz
141
- - **x402scan**: https://x402scan.com/server/mcp.cryptoiz.org
142
-
143
- ## License
144
-
145
- MIT © CryptoIZ
1
+ # cryptoiz-mcp
2
+
3
+ [![npm version](https://img.shields.io/npm/v/cryptoiz-mcp.svg)](https://www.npmjs.com/package/cryptoiz-mcp)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![x402scan](https://img.shields.io/badge/x402scan-listed-blue)](https://x402scan.com/server/cbd8fff5-d636-4331-b22b-3291717a4e9e)
6
+ [![MCP Marketplace](https://img.shields.io/badge/MCP_Marketplace-listed-green)](https://mcp-marketplace.io/server/io-github-dadang11-cryptoiz)
7
+
8
+ **CryptoIZ MCP Server** — Solana DEX whale intelligence as a Model Context Protocol (MCP) server. 9 tools (7 paid + 2 free) for Claude Desktop, Cursor, Codex, and any agentcash-compatible client. Native Solana via x402 V2 + Dexter facilitator (gas-sponsored — no SOL needed, only USDC).
9
+
10
+ ## ⚡ Recommended Install (1 line)
11
+
12
+ ```bash
13
+ npx agentcash add https://mcp.cryptoiz.org
14
+ ```
15
+
16
+ That's it. agentcash auto-generates a Solana wallet at `~/.agentcash/wallet.json` (no private key in your Claude config). Fund with $1-5 USDC via `npx agentcash fund` and you're ready.
17
+
18
+ **Why agentcash:**
19
+ - ✅ No private key in Claude Desktop config
20
+ - ✅ Wallet auto-generated and isolated
21
+ - ✅ Gas sponsored by Dexter (zero SOL needed)
22
+ - ✅ Update tools without reinstalling client
23
+ - ✅ One wallet across ALL x402 services (CryptoIZ, HYRE, etc.)
24
+
25
+ ## 5 Specialized Sub-Agents
26
+
27
+ Pick what you need:
28
+
29
+ ```bash
30
+ npx agentcash add https://mcp.cryptoiz.org/agents/alpha # Whale alpha signals only
31
+ npx agentcash add https://mcp.cryptoiz.org/agents/btc # BTC regime + futures
32
+ npx agentcash add https://mcp.cryptoiz.org/agents/phases # Accumulation/Neutral/Distribution
33
+ npx agentcash add https://mcp.cryptoiz.org/agents/divergence # Divergence patterns
34
+ npx agentcash add https://mcp.cryptoiz.org/agents/deep-research # Token deep-dive combo
35
+ ```
36
+
37
+ ## Tools & Pricing
38
+
39
+ | Tool | Cost | Description |
40
+ |---|---|---|
41
+ | `get_whale_alpha` | $0.10 USDC | Top 20 alpha signals — whale/dolphin accumulation, entry timing |
42
+ | `get_whale_divergence` | $0.04 USDC | Hidden/breakout/classic divergence signals (4h/1d) |
43
+ | `get_whale_accumulation` | $0.03 USDC | Tokens with smart money accumulating |
44
+ | `get_whale_neutral` | $0.03 USDC | Tokens in transition phase |
45
+ | `get_whale_distribution` | $0.04 USDC | Tokens with whales selling (exit signal) |
46
+ | `get_btc_regime` | $0.02 USDC | BTC macro regime + sentiment + technicals |
47
+ | `get_btc_futures_signal` | $0.06 USDC | BTC futures multi-timeframe signal (54% WR) |
48
+ | `get_token_ca` | FREE | Look up Solana contract address by name |
49
+ | `get_status` | FREE | Server status, available tools, pricing |
50
+
51
+ All payments settle on Solana mainnet via [Dexter facilitator](https://x402.dexter.cash). Recipient: `DsKmdkYx49Xc1WhqMUAztwhdYPTqieyC98VmnnJdgpXX`.
52
+
53
+ ## Legacy Setup (Advanced — not recommended)
54
+
55
+ For users who prefer self-custody with their own Solana wallet:
56
+
57
+ ### 1. Install the package globally
58
+
59
+ ```bash
60
+ npm install -g cryptoiz-mcp
61
+ ```
62
+
63
+ ### 2. Get a Solana wallet private key (base58)
64
+
65
+ You need a Solana wallet with at least **$1 USDC** on mainnet. **No SOL needed** — Dexter sponsors all gas. Recommended: dedicated wallet, NOT your main wallet. Phantom: Settings > Security > Export Private Key.
66
+
67
+ ### 3. Edit Claude Desktop config
68
+
69
+ File: `%APPDATA%\Claude\claude_desktop_config.json` (Windows) or `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS).
70
+
71
+ ```json
72
+ {
73
+ "mcpServers": {
74
+ "cryptoiz": {
75
+ "command": "C:\\Program Files\\nodejs\\node.exe",
76
+ "args": ["C:\\Users\\<YOU>\\AppData\\Roaming\\npm\\node_modules\\cryptoiz-mcp\\index.js"],
77
+ "env": {
78
+ "SVM_PRIVATE_KEY": "<your_base58_solana_private_key>"
79
+ }
80
+ }
81
+ }
82
+ }
83
+ ```
84
+
85
+ ### 4. Restart Claude Desktop
86
+
87
+ Then ask Claude: `get cryptoiz status` — you should see version `v4.16.17` and the tool list.
88
+
89
+ ## Security
90
+
91
+ - **agentcash flow** (recommended): private key auto-generated and isolated, never in Claude config
92
+ - **Gas-sponsored**: Dexter facilitator pays all gas (you only pay USDC)
93
+ - **Server-side validation**: every payment verified via Dexter `/settle` before serving data
94
+ - **x402 V2 spec compliant**: open standard, no custom protocol
95
+ - **No tracking**: only on-chain transaction signature is recorded for replay protection
96
+ - **Dedicated wallet recommended** for legacy npm install (don't use your main wallet)
97
+
98
+ ## Listed at
99
+
100
+ - [MCP Marketplace](https://mcp-marketplace.io/server/io-github-dadang11-cryptoiz)
101
+ - [x402scan](https://x402scan.com/server/cbd8fff5-d636-4331-b22b-3291717a4e9e) — 94+ tx, $2.80+ volume
102
+ - [Official MCP Registry](https://github.com/modelcontextprotocol/registry)
103
+ - MPPscan (pending)
104
+
105
+ ## Architecture
106
+
107
+ ```
108
+ Claude Desktop / Cursor / Codex
109
+ │ (MCP)
110
+
111
+ agentcash CLI (or cryptoiz-mcp legacy npm)
112
+ │ (HTTP)
113
+
114
+ mcp.cryptoiz.org gateway (Cloudflare Worker + Supabase Edge Function)
115
+ │ (POST /settle)
116
+
117
+ Dexter facilitator (x402.dexter.cash)
118
+ │ (signs + broadcasts)
119
+
120
+ Solana mainnet
121
+ ```
122
+
123
+ ## Troubleshooting
124
+
125
+ ### "Transaction simulation failed"
126
+ Update to latest: `npx agentcash add https://mcp.cryptoiz.org` (or `npm install -g cryptoiz-mcp@latest` for legacy).
127
+
128
+ ### "Server disconnected" on Windows
129
+ Use absolute paths in Claude config (legacy npm only). agentcash flow doesn't have this issue.
130
+
131
+ ### Update notifications keep showing
132
+ Run `npm install -g cryptoiz-mcp@latest`, force-kill all `node.exe` processes via Task Manager, then restart Claude Desktop. Or switch to agentcash for auto-updates.
133
+
134
+ ## Links
135
+
136
+ - **Platform**: https://cryptoiz.org
137
+ - **Setup guide**: https://cryptoiz.org/McpLanding
138
+ - **Twitter**: [@cryptoiz_IDN](https://twitter.com/cryptoiz_IDN)
139
+ - **Telegram**: https://t.me/agus_artemiss
140
+ - **MCP Marketplace**: https://mcp-marketplace.io/server/io-github-dadang11-cryptoiz
141
+ - **x402scan**: https://x402scan.com/server/mcp.cryptoiz.org
142
+
143
+ ## License
144
+
145
+ MIT © CryptoIZ
package/index.js CHANGED
@@ -1,309 +1,309 @@
1
- 'use strict';
2
- var VERSION = 'v4.16.15';
3
- var GATEWAY = 'https://rehqwsypjnjirhuiapqh.supabase.co/functions/v1/mcp-x402-gateway';
4
- // FIX v4.16.12: route ALL paid tools to gateway. Per-tool endpoints (mcp-alpha-scanner etc.)
5
- // have stale hardcoded fee payer that breaks after Dexter key rotation. Gateway has dynamic
6
- // fee payer fetched from /supported. Single source of truth = no per-tool drift.
7
- var TOOL_ENDPOINTS = {
8
- get_whale_alpha: GATEWAY,
9
- get_whale_divergence: GATEWAY,
10
- get_whale_accumulation: GATEWAY,
11
- get_whale_neutral: GATEWAY,
12
- get_whale_distribution: GATEWAY,
13
- get_btc_regime: GATEWAY,
14
- get_btc_futures_signal: GATEWAY,
15
- get_token_ca: GATEWAY,
16
- get_status: GATEWAY,
17
- };
18
- var RECIPIENT = 'DsKmdkYx49Xc1WhqMUAztwhdYPTqieyC98VmnnJdgpXX';
19
- var USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
20
- var SOL_RPC = 'https://api.mainnet-beta.solana.com';
21
- var TOKEN_PROGRAM = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA';
22
- var ATA_PROGRAM = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL';
23
- var MEMO_PROGRAM = 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr';
24
- var COMPUTE_BUDGET_PROGRAM = 'ComputeBudget111111111111111111111111111111';
25
-
26
- var _updateNotified = false;
27
- function notifyUpdate(data, headers) {
28
- if (_updateNotified) return;
29
- if (!headers || headers.get('x-update-available') !== '1') return;
30
- _updateNotified = true;
31
- var latest = (data && data.version_latest) || '?';
32
- var cmd = (data && data.update_command) || 'npm install -g cryptoiz-mcp@latest';
33
- console.error('[cryptoiz-mcp] UPDATE: ' + VERSION + ' -> ' + latest + ' | Run: ' + cmd);
34
- }
35
-
36
- var solana = require('@solana/web3.js');
37
- var Connection = solana.Connection;
38
- var PublicKey = solana.PublicKey;
39
- var Transaction = solana.Transaction;
40
- var TransactionMessage = solana.TransactionMessage;
41
- var VersionedTransaction = solana.VersionedTransaction;
42
- var Keypair = solana.Keypair;
43
- // Fix bs58 v6 ESM-only issue: support both CJS (v5) and ESM-compiled (v6)
44
- var _bs58mod = require('bs58');
45
- var bs58 = _bs58mod.default || _bs58mod;
46
- var Server = require('@modelcontextprotocol/sdk/server/index.js').Server;
47
- var StdioServerTransport = require('@modelcontextprotocol/sdk/server/stdio.js').StdioServerTransport;
48
- var CallToolRequestSchema = require('@modelcontextprotocol/sdk/types.js').CallToolRequestSchema;
49
- var ListToolsRequestSchema = require('@modelcontextprotocol/sdk/types.js').ListToolsRequestSchema;
50
-
51
- function getKeypair() {
52
- var privKey = process.env.SVM_PRIVATE_KEY;
53
- if (!privKey) throw new Error('SVM_PRIVATE_KEY not set in environment');
54
- return Keypair.fromSecretKey(bs58.decode(privKey));
55
- }
56
-
57
- function findATA(wallet, mint) {
58
- var walletPk = new PublicKey(wallet);
59
- var mintPk = new PublicKey(mint);
60
- var ataPk = new PublicKey(ATA_PROGRAM);
61
- var tokPk = new PublicKey(TOKEN_PROGRAM);
62
- return PublicKey.findProgramAddressSync([walletPk.toBuffer(), tokPk.toBuffer(), mintPk.toBuffer()], ataPk)[0];
63
- }
64
-
65
- // V2: Dexter gas-sponsored. 4-ix tx: Limit + Price + TransferChecked + Memo(nonce)
66
- // Dexter pays SOL gas — user only needs USDC
67
- async function buildV2PaymentPayload(amount, feePayerAddr) {
68
- var kp = getKeypair();
69
- var conn = new Connection(SOL_RPC, 'confirmed');
70
- var userATA = findATA(kp.publicKey.toBase58(), USDC_MINT);
71
- var recipientATA = findATA(RECIPIENT, USDC_MINT);
72
- var feePayerPk = new PublicKey(feePayerAddr);
73
- var computeBudgetPk = new PublicKey(COMPUTE_BUDGET_PROGRAM);
74
- var tokenProgramPk = new PublicKey(TOKEN_PROGRAM);
75
- var usdcMintPk = new PublicKey(USDC_MINT);
76
- // FIX v4.16.13: ComputeUnitLimit 20000 -> 30000.
77
- // Memo program needs >13500 CU when content is 'x402:v2:'+32char hex; old (April 6-8)
78
- // working code used just 32-char nonceHex which fit in 20000 budget. Bumping limit gives
79
- // headroom for slightly longer memo content. Dexter spec allows up to 40000.
80
- var setLimitData = Buffer.alloc(5);
81
- setLimitData[0] = 0x02;
82
- setLimitData.writeUInt32LE(30000, 1);
83
- var setLimitIx = { programId: computeBudgetPk, keys: [], data: setLimitData };
84
- // ComputeUnitPrice(1)
85
- var setPriceData = Buffer.alloc(9);
86
- setPriceData[0] = 0x03;
87
- setPriceData.writeBigUInt64LE(BigInt(1), 1);
88
- var setPriceIx = { programId: computeBudgetPk, keys: [], data: setPriceData };
89
- // TransferChecked
90
- var transferKeys = [
91
- { pubkey: userATA, isSigner: false, isWritable: true },
92
- { pubkey: usdcMintPk, isSigner: false, isWritable: false },
93
- { pubkey: recipientATA, isSigner: false, isWritable: true },
94
- { pubkey: kp.publicKey, isSigner: true, isWritable: false },
95
- ];
96
- var transferData = Buffer.alloc(10);
97
- transferData[0] = 0x0c;
98
- transferData.writeUInt32LE(amount & 0xFFFFFFFF, 1);
99
- transferData.writeUInt32LE(Math.floor(amount / 0x100000000) & 0xFFFFFFFF, 5);
100
- transferData[9] = 6;
101
- var transferIx = { programId: tokenProgramPk, keys: transferKeys, data: transferData };
102
- // FIX v4.16.12: RESTORE Memo instruction in V2 (4-ix tx: Limit+Price+TransferChecked+Memo).
103
- // Empirical: April 6-8 logs prove V2 with memo accepted by Dexter. Removing memo (v4.16.10)
104
- // didn't fix anything — the actual bug was Dexter key rotation, fixed in gateway v44.
105
- // Memo also makes TX visible to x402scan (memo carries x402 nonce marker).
106
- var memoProgramPk = new PublicKey(MEMO_PROGRAM);
107
- var nonceBytes = new Uint8Array(16);
108
- for (var i = 0; i < 16; i++) nonceBytes[i] = Math.floor(Math.random() * 256);
109
- var nonceHex = Array.from(nonceBytes).map(function(b) { return b.toString(16).padStart(2,'0'); }).join('');
110
- // FIX v4.16.13: memo = just nonceHex (matches April 6-8 working V2 format).
111
- // Adding 'x402:v2:' prefix made memo too long for 20000 CU budget.
112
- var memoIx = { programId: memoProgramPk, keys: [], data: Buffer.from(nonceHex, 'utf8') };
113
- var bh = await conn.getLatestBlockhash('confirmed');
114
- var message = new TransactionMessage({
115
- payerKey: feePayerPk,
116
- recentBlockhash: bh.blockhash,
117
- instructions: [setLimitIx, setPriceIx, transferIx, memoIx],
118
- }).compileToV0Message();
119
- var vtx = new VersionedTransaction(message);
120
- vtx.sign([kp]);
121
- var txB64 = Buffer.from(vtx.serialize()).toString('base64');
122
- console.error('[cryptoiz-mcp] V2 tx built (Dexter gas-sponsored), 4 ix limit=30000');
123
- return txB64;
124
- }
125
-
126
- // V1: direct on-chain, user pays SOL gas (fallback only)
127
- async function sendUSDC(amount, toolName) {
128
- var kp = getKeypair();
129
- var conn = new Connection(SOL_RPC, 'confirmed');
130
- var userATA = findATA(kp.publicKey.toBase58(), USDC_MINT);
131
- var recipientATA = findATA(RECIPIENT, USDC_MINT);
132
- var keys = [
133
- { pubkey: userATA, isSigner: false, isWritable: true },
134
- { pubkey: new PublicKey(USDC_MINT), isSigner: false, isWritable: false },
135
- { pubkey: recipientATA, isSigner: false, isWritable: true },
136
- { pubkey: kp.publicKey, isSigner: true, isWritable: false },
137
- ];
138
- // FIX v4.16.10: TransferChecked needs 10 bytes (1 disc + 8 amount + 1 decimals)
139
- var data = Buffer.alloc(10);
140
- data[0] = 0x0c;
141
- data.writeUInt32LE(amount & 0xFFFFFFFF, 1);
142
- data.writeUInt32LE(Math.floor(amount / 0x100000000) & 0xFFFFFFFF, 5);
143
- data[9] = 6;
144
- var transferIx = { programId: new PublicKey(TOKEN_PROGRAM), keys: keys, data: data };
145
- var nonce = Date.now().toString(16) + Math.floor(Math.random()*0xffff).toString(16);
146
- var memoIx = {
147
- programId: new PublicKey(MEMO_PROGRAM),
148
- keys: [],
149
- data: Buffer.from('x402:v1:' + (toolName || 'tool') + ':' + nonce, 'utf8')
150
- };
151
- var bh = await conn.getLatestBlockhash('confirmed');
152
- var tx = new Transaction({ feePayer: kp.publicKey, blockhash: bh.blockhash, lastValidBlockHeight: bh.lastValidBlockHeight });
153
- tx.add(memoIx);
154
- tx.add(transferIx);
155
- tx.sign(kp);
156
- var sig = await conn.sendRawTransaction(tx.serialize(), { skipPreflight: false });
157
- await conn.confirmTransaction({ signature: sig, blockhash: bh.blockhash, lastValidBlockHeight: bh.lastValidBlockHeight }, 'confirmed');
158
- console.error('[cryptoiz-mcp] V1 TX: ' + sig);
159
- return sig;
160
- }
161
-
162
- function clientHeaders(extra) {
163
- var h = { 'x-client-version': VERSION.replace(/^v/i, '') };
164
- if (extra) for (var k in extra) if (Object.prototype.hasOwnProperty.call(extra, k)) h[k] = extra[k];
165
- return h;
166
- }
167
-
168
- // v4.16.14: input validation per tool — defense in depth, server-side double-validates.
169
- function validateArgs(toolName, args) {
170
- if (args == null) return {}; // Empty args ok
171
- if (typeof args !== 'object' || Array.isArray(args)) {
172
- throw new Error('Invalid args: expected object, got ' + typeof args);
173
- }
174
- var clean = {};
175
- if (toolName === 'get_whale_divergence') {
176
- if (args.timeframe != null) {
177
- if (typeof args.timeframe !== 'string') throw new Error('timeframe must be string');
178
- if (args.timeframe !== '4h' && args.timeframe !== '1d') throw new Error("timeframe must be '4h' or '1d'");
179
- clean.timeframe = args.timeframe;
180
- }
181
- } else if (toolName === 'get_token_ca') {
182
- if (args.name == null) throw new Error('name is required for get_token_ca');
183
- if (typeof args.name !== 'string') throw new Error('name must be string');
184
- var trimmed = args.name.trim();
185
- if (trimmed.length < 1 || trimmed.length > 64) throw new Error('name length must be 1-64 chars');
186
- if (!/^[a-zA-Z0-9 _\-\$\.\u00c0-\uffff]+$/.test(trimmed)) throw new Error('name contains invalid chars');
187
- clean.name = trimmed;
188
- }
189
- // Other tools accept no args — anything passed is silently dropped.
190
- return clean;
191
- }
192
-
193
- async function callTool(toolName, args) {
194
- args = validateArgs(toolName, args);
195
- var queryParts = ['tool=' + toolName];
196
- if (toolName === 'get_whale_divergence' && args && args.timeframe) queryParts.push('tf=' + args.timeframe);
197
- if (toolName === 'get_token_ca' && args && args.name) queryParts.push('name=' + encodeURIComponent(args.name));
198
- var url = (TOOL_ENDPOINTS[toolName] || GATEWAY) + '?' + queryParts.join('&');
199
-
200
- // Step 1: discovery
201
- var resp1 = await fetch(url, { headers: clientHeaders() });
202
- if (resp1.status === 200) { var d = await resp1.json(); notifyUpdate(d, resp1.headers); return d; }
203
- if (resp1.status !== 402) throw new Error('Server error ' + resp1.status + ': ' + (await resp1.text()).substring(0, 200));
204
-
205
- // Step 2: parse payment requirements
206
- // FIX v4.16.11: detect V2 by extra.feePayer presence (Dexter sponsorship marker),
207
- // not by header. Per-tool endpoints (mcp-alpha-scanner, mcp-btc-regime, etc.) only
208
- // serve 402 in body, no payment-required header. Header check stays as fast path.
209
- var payReq = null;
210
- var prHeader = resp1.headers.get('payment-required');
211
- if (prHeader) {
212
- try {
213
- var arr = JSON.parse(Buffer.from(prHeader, 'base64').toString('utf8'));
214
- if (arr && arr[0]) payReq = arr[0];
215
- } catch(_e) {}
216
- }
217
- if (!payReq) {
218
- var b402 = await resp1.json();
219
- if (b402 && b402.accepts && b402.accepts[0]) payReq = b402.accepts[0];
220
- }
221
- if (!payReq) throw new Error('No payment requirements in 402');
222
- // V2 = Dexter sponsored gas = extra.feePayer field present (independent of transport)
223
- var useV2 = !!(payReq.extra && payReq.extra.feePayer);
224
-
225
- var amount = parseInt(payReq.maxAmountRequired || payReq.amount || '10000');
226
- var hasFeePayer = payReq.extra && payReq.extra.feePayer;
227
- var paymentHeader = '';
228
- var headerName = '';
229
-
230
- // Step 3: Try V2 Dexter (gas-sponsored by Dexter — user only needs USDC)
231
- if (useV2 && hasFeePayer) {
232
- console.error('[cryptoiz-mcp] V2 mode: Dexter gas-sponsored, paying ' + (amount/1000000).toFixed(4) + ' USDC');
233
- try {
234
- var txB64 = await buildV2PaymentPayload(amount, payReq.extra.feePayer);
235
- // FIX v4.16.10: x402Version:2 (was 1), add 'accepted' (chosen PaymentRequirements
236
- // verbatim — Dexter /verify needs this to match amount/asset/payTo). Removed bogus
237
- // signature field — V2 schema only has payload.transaction.
238
- var v2Payload = {
239
- x402Version: 2,
240
- scheme: 'exact',
241
- network: payReq.network || 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
242
- accepted: payReq,
243
- payload: { transaction: txB64 },
244
- extensions: {}
245
- };
246
- paymentHeader = Buffer.from(JSON.stringify(v2Payload)).toString('base64');
247
- headerName = 'payment-signature';
248
- } catch(v2Err) {
249
- console.error('[cryptoiz-mcp] V2 build failed: ' + v2Err.message + ' -> fallback V1');
250
- useV2 = false;
251
- }
252
- }
253
-
254
- // Step 4: V1 fallback (user pays gas — only if V2 failed)
255
- if (!paymentHeader) {
256
- console.error('[cryptoiz-mcp] V1 fallback: direct on-chain transfer');
257
- var sig = await sendUSDC(amount, toolName);
258
- paymentHeader = Buffer.from(JSON.stringify({ signature: sig })).toString('base64');
259
- headerName = 'x-payment';
260
- }
261
-
262
- // Step 5: submit payment
263
- var headers2 = {};
264
- headers2[headerName] = paymentHeader;
265
- var resp2 = await fetch(url, { headers: clientHeaders(headers2) });
266
-
267
- // Step 6: if V2 failed at server, retry with V1
268
- if (resp2.status !== 200 && useV2) {
269
- console.error('[cryptoiz-mcp] V2 settle failed, trying V1 fallback...');
270
- var fallbackSig = await sendUSDC(amount, toolName);
271
- var v1Header = Buffer.from(JSON.stringify({ signature: fallbackSig })).toString('base64');
272
- resp2 = await fetch(url, { headers: clientHeaders({ 'x-payment': v1Header }) });
273
- }
274
-
275
- if (resp2.status !== 200) throw new Error('Payment failed ' + resp2.status + ': ' + (await resp2.text()).substring(0, 300));
276
- var data = await resp2.json();
277
- notifyUpdate(data, resp2.headers);
278
- return data;
279
- }
280
-
281
- var TOOLS = [
282
- { name: 'get_whale_alpha', description: 'Alpha scanner - early accumulation tokens. Cost: $0.05 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
283
- { name: 'get_whale_divergence', description: 'Whale divergence signals. Cost: $0.02 USDC', inputSchema: { type: 'object', properties: { timeframe: { type: 'string', enum: ['4h', '1d'] } }, additionalProperties: false } },
284
- { name: 'get_whale_accumulation', description: 'Accumulation phase tokens. Cost: $0.02 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
285
- { name: 'get_whale_neutral', description: 'Neutral phase tokens. Cost: $0.02 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
286
- { name: 'get_whale_distribution', description: 'Distribution phase tokens. Cost: $0.02 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
287
- { name: 'get_btc_regime', description: 'BTC macro regime. Cost: $0.01 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
288
- { name: 'get_btc_futures_signal', description: 'BTC futures signal. Cost: $0.03 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
289
- { name: 'get_token_ca', description: 'Token contract address. FREE', inputSchema: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'], additionalProperties: false } },
290
- { name: 'get_status', description: 'CryptoIZ MCP status. FREE', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
291
- ];
292
-
293
- var server = new Server({ name: 'cryptoiz-mcp', version: VERSION }, { capabilities: { tools: {} } });
294
- server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
295
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
296
- try {
297
- var result = await callTool(request.params.name, request.params.arguments || {});
298
- return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
299
- } catch(e) {
300
- return { content: [{ type: 'text', text: 'Error: ' + e.message }], isError: true };
301
- }
302
- });
303
-
304
- async function main() {
305
- var transport = new StdioServerTransport();
306
- await server.connect(transport);
307
- console.error('[cryptoiz-mcp] ' + VERSION + ' running (V2 Dexter gas-sponsored + V1 fallback)');
308
- }
309
- main().catch(console.error);
1
+ 'use strict';
2
+ var VERSION = 'v4.16.15';
3
+ var GATEWAY = 'https://rehqwsypjnjirhuiapqh.supabase.co/functions/v1/mcp-x402-gateway';
4
+ // FIX v4.16.12: route ALL paid tools to gateway. Per-tool endpoints (mcp-alpha-scanner etc.)
5
+ // have stale hardcoded fee payer that breaks after Dexter key rotation. Gateway has dynamic
6
+ // fee payer fetched from /supported. Single source of truth = no per-tool drift.
7
+ var TOOL_ENDPOINTS = {
8
+ get_whale_alpha: GATEWAY,
9
+ get_whale_divergence: GATEWAY,
10
+ get_whale_accumulation: GATEWAY,
11
+ get_whale_neutral: GATEWAY,
12
+ get_whale_distribution: GATEWAY,
13
+ get_btc_regime: GATEWAY,
14
+ get_btc_futures_signal: GATEWAY,
15
+ get_token_ca: GATEWAY,
16
+ get_status: GATEWAY,
17
+ };
18
+ var RECIPIENT = 'DsKmdkYx49Xc1WhqMUAztwhdYPTqieyC98VmnnJdgpXX';
19
+ var USDC_MINT = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
20
+ var SOL_RPC = 'https://api.mainnet-beta.solana.com';
21
+ var TOKEN_PROGRAM = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA';
22
+ var ATA_PROGRAM = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL';
23
+ var MEMO_PROGRAM = 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr';
24
+ var COMPUTE_BUDGET_PROGRAM = 'ComputeBudget111111111111111111111111111111';
25
+
26
+ var _updateNotified = false;
27
+ function notifyUpdate(data, headers) {
28
+ if (_updateNotified) return;
29
+ if (!headers || headers.get('x-update-available') !== '1') return;
30
+ _updateNotified = true;
31
+ var latest = (data && data.version_latest) || '?';
32
+ var cmd = (data && data.update_command) || 'npm install -g cryptoiz-mcp@latest';
33
+ console.error('[cryptoiz-mcp] UPDATE: ' + VERSION + ' -> ' + latest + ' | Run: ' + cmd);
34
+ }
35
+
36
+ var solana = require('@solana/web3.js');
37
+ var Connection = solana.Connection;
38
+ var PublicKey = solana.PublicKey;
39
+ var Transaction = solana.Transaction;
40
+ var TransactionMessage = solana.TransactionMessage;
41
+ var VersionedTransaction = solana.VersionedTransaction;
42
+ var Keypair = solana.Keypair;
43
+ // Fix bs58 v6 ESM-only issue: support both CJS (v5) and ESM-compiled (v6)
44
+ var _bs58mod = require('bs58');
45
+ var bs58 = _bs58mod.default || _bs58mod;
46
+ var Server = require('@modelcontextprotocol/sdk/server/index.js').Server;
47
+ var StdioServerTransport = require('@modelcontextprotocol/sdk/server/stdio.js').StdioServerTransport;
48
+ var CallToolRequestSchema = require('@modelcontextprotocol/sdk/types.js').CallToolRequestSchema;
49
+ var ListToolsRequestSchema = require('@modelcontextprotocol/sdk/types.js').ListToolsRequestSchema;
50
+
51
+ function getKeypair() {
52
+ var privKey = process.env.SVM_PRIVATE_KEY;
53
+ if (!privKey) throw new Error('SVM_PRIVATE_KEY not set in environment');
54
+ return Keypair.fromSecretKey(bs58.decode(privKey));
55
+ }
56
+
57
+ function findATA(wallet, mint) {
58
+ var walletPk = new PublicKey(wallet);
59
+ var mintPk = new PublicKey(mint);
60
+ var ataPk = new PublicKey(ATA_PROGRAM);
61
+ var tokPk = new PublicKey(TOKEN_PROGRAM);
62
+ return PublicKey.findProgramAddressSync([walletPk.toBuffer(), tokPk.toBuffer(), mintPk.toBuffer()], ataPk)[0];
63
+ }
64
+
65
+ // V2: Dexter gas-sponsored. 4-ix tx: Limit + Price + TransferChecked + Memo(nonce)
66
+ // Dexter pays SOL gas — user only needs USDC
67
+ async function buildV2PaymentPayload(amount, feePayerAddr) {
68
+ var kp = getKeypair();
69
+ var conn = new Connection(SOL_RPC, 'confirmed');
70
+ var userATA = findATA(kp.publicKey.toBase58(), USDC_MINT);
71
+ var recipientATA = findATA(RECIPIENT, USDC_MINT);
72
+ var feePayerPk = new PublicKey(feePayerAddr);
73
+ var computeBudgetPk = new PublicKey(COMPUTE_BUDGET_PROGRAM);
74
+ var tokenProgramPk = new PublicKey(TOKEN_PROGRAM);
75
+ var usdcMintPk = new PublicKey(USDC_MINT);
76
+ // FIX v4.16.13: ComputeUnitLimit 20000 -> 30000.
77
+ // Memo program needs >13500 CU when content is 'x402:v2:'+32char hex; old (April 6-8)
78
+ // working code used just 32-char nonceHex which fit in 20000 budget. Bumping limit gives
79
+ // headroom for slightly longer memo content. Dexter spec allows up to 40000.
80
+ var setLimitData = Buffer.alloc(5);
81
+ setLimitData[0] = 0x02;
82
+ setLimitData.writeUInt32LE(30000, 1);
83
+ var setLimitIx = { programId: computeBudgetPk, keys: [], data: setLimitData };
84
+ // ComputeUnitPrice(1)
85
+ var setPriceData = Buffer.alloc(9);
86
+ setPriceData[0] = 0x03;
87
+ setPriceData.writeBigUInt64LE(BigInt(1), 1);
88
+ var setPriceIx = { programId: computeBudgetPk, keys: [], data: setPriceData };
89
+ // TransferChecked
90
+ var transferKeys = [
91
+ { pubkey: userATA, isSigner: false, isWritable: true },
92
+ { pubkey: usdcMintPk, isSigner: false, isWritable: false },
93
+ { pubkey: recipientATA, isSigner: false, isWritable: true },
94
+ { pubkey: kp.publicKey, isSigner: true, isWritable: false },
95
+ ];
96
+ var transferData = Buffer.alloc(10);
97
+ transferData[0] = 0x0c;
98
+ transferData.writeUInt32LE(amount & 0xFFFFFFFF, 1);
99
+ transferData.writeUInt32LE(Math.floor(amount / 0x100000000) & 0xFFFFFFFF, 5);
100
+ transferData[9] = 6;
101
+ var transferIx = { programId: tokenProgramPk, keys: transferKeys, data: transferData };
102
+ // FIX v4.16.12: RESTORE Memo instruction in V2 (4-ix tx: Limit+Price+TransferChecked+Memo).
103
+ // Empirical: April 6-8 logs prove V2 with memo accepted by Dexter. Removing memo (v4.16.10)
104
+ // didn't fix anything — the actual bug was Dexter key rotation, fixed in gateway v44.
105
+ // Memo also makes TX visible to x402scan (memo carries x402 nonce marker).
106
+ var memoProgramPk = new PublicKey(MEMO_PROGRAM);
107
+ var nonceBytes = new Uint8Array(16);
108
+ for (var i = 0; i < 16; i++) nonceBytes[i] = Math.floor(Math.random() * 256);
109
+ var nonceHex = Array.from(nonceBytes).map(function(b) { return b.toString(16).padStart(2,'0'); }).join('');
110
+ // FIX v4.16.13: memo = just nonceHex (matches April 6-8 working V2 format).
111
+ // Adding 'x402:v2:' prefix made memo too long for 20000 CU budget.
112
+ var memoIx = { programId: memoProgramPk, keys: [], data: Buffer.from(nonceHex, 'utf8') };
113
+ var bh = await conn.getLatestBlockhash('confirmed');
114
+ var message = new TransactionMessage({
115
+ payerKey: feePayerPk,
116
+ recentBlockhash: bh.blockhash,
117
+ instructions: [setLimitIx, setPriceIx, transferIx, memoIx],
118
+ }).compileToV0Message();
119
+ var vtx = new VersionedTransaction(message);
120
+ vtx.sign([kp]);
121
+ var txB64 = Buffer.from(vtx.serialize()).toString('base64');
122
+ console.error('[cryptoiz-mcp] V2 tx built (Dexter gas-sponsored), 4 ix limit=30000');
123
+ return txB64;
124
+ }
125
+
126
+ // V1: direct on-chain, user pays SOL gas (fallback only)
127
+ async function sendUSDC(amount, toolName) {
128
+ var kp = getKeypair();
129
+ var conn = new Connection(SOL_RPC, 'confirmed');
130
+ var userATA = findATA(kp.publicKey.toBase58(), USDC_MINT);
131
+ var recipientATA = findATA(RECIPIENT, USDC_MINT);
132
+ var keys = [
133
+ { pubkey: userATA, isSigner: false, isWritable: true },
134
+ { pubkey: new PublicKey(USDC_MINT), isSigner: false, isWritable: false },
135
+ { pubkey: recipientATA, isSigner: false, isWritable: true },
136
+ { pubkey: kp.publicKey, isSigner: true, isWritable: false },
137
+ ];
138
+ // FIX v4.16.10: TransferChecked needs 10 bytes (1 disc + 8 amount + 1 decimals)
139
+ var data = Buffer.alloc(10);
140
+ data[0] = 0x0c;
141
+ data.writeUInt32LE(amount & 0xFFFFFFFF, 1);
142
+ data.writeUInt32LE(Math.floor(amount / 0x100000000) & 0xFFFFFFFF, 5);
143
+ data[9] = 6;
144
+ var transferIx = { programId: new PublicKey(TOKEN_PROGRAM), keys: keys, data: data };
145
+ var nonce = Date.now().toString(16) + Math.floor(Math.random()*0xffff).toString(16);
146
+ var memoIx = {
147
+ programId: new PublicKey(MEMO_PROGRAM),
148
+ keys: [],
149
+ data: Buffer.from('x402:v1:' + (toolName || 'tool') + ':' + nonce, 'utf8')
150
+ };
151
+ var bh = await conn.getLatestBlockhash('confirmed');
152
+ var tx = new Transaction({ feePayer: kp.publicKey, blockhash: bh.blockhash, lastValidBlockHeight: bh.lastValidBlockHeight });
153
+ tx.add(memoIx);
154
+ tx.add(transferIx);
155
+ tx.sign(kp);
156
+ var sig = await conn.sendRawTransaction(tx.serialize(), { skipPreflight: false });
157
+ await conn.confirmTransaction({ signature: sig, blockhash: bh.blockhash, lastValidBlockHeight: bh.lastValidBlockHeight }, 'confirmed');
158
+ console.error('[cryptoiz-mcp] V1 TX: ' + sig);
159
+ return sig;
160
+ }
161
+
162
+ function clientHeaders(extra) {
163
+ var h = { 'x-client-version': VERSION.replace(/^v/i, '') };
164
+ if (extra) for (var k in extra) if (Object.prototype.hasOwnProperty.call(extra, k)) h[k] = extra[k];
165
+ return h;
166
+ }
167
+
168
+ // v4.16.14: input validation per tool — defense in depth, server-side double-validates.
169
+ function validateArgs(toolName, args) {
170
+ if (args == null) return {}; // Empty args ok
171
+ if (typeof args !== 'object' || Array.isArray(args)) {
172
+ throw new Error('Invalid args: expected object, got ' + typeof args);
173
+ }
174
+ var clean = {};
175
+ if (toolName === 'get_whale_divergence') {
176
+ if (args.timeframe != null) {
177
+ if (typeof args.timeframe !== 'string') throw new Error('timeframe must be string');
178
+ if (args.timeframe !== '4h' && args.timeframe !== '1d') throw new Error("timeframe must be '4h' or '1d'");
179
+ clean.timeframe = args.timeframe;
180
+ }
181
+ } else if (toolName === 'get_token_ca') {
182
+ if (args.name == null) throw new Error('name is required for get_token_ca');
183
+ if (typeof args.name !== 'string') throw new Error('name must be string');
184
+ var trimmed = args.name.trim();
185
+ if (trimmed.length < 1 || trimmed.length > 64) throw new Error('name length must be 1-64 chars');
186
+ if (!/^[a-zA-Z0-9 _\-\$\.\u00c0-\uffff]+$/.test(trimmed)) throw new Error('name contains invalid chars');
187
+ clean.name = trimmed;
188
+ }
189
+ // Other tools accept no args — anything passed is silently dropped.
190
+ return clean;
191
+ }
192
+
193
+ async function callTool(toolName, args) {
194
+ args = validateArgs(toolName, args);
195
+ var queryParts = ['tool=' + toolName];
196
+ if (toolName === 'get_whale_divergence' && args && args.timeframe) queryParts.push('tf=' + args.timeframe);
197
+ if (toolName === 'get_token_ca' && args && args.name) queryParts.push('name=' + encodeURIComponent(args.name));
198
+ var url = (TOOL_ENDPOINTS[toolName] || GATEWAY) + '?' + queryParts.join('&');
199
+
200
+ // Step 1: discovery
201
+ var resp1 = await fetch(url, { headers: clientHeaders() });
202
+ if (resp1.status === 200) { var d = await resp1.json(); notifyUpdate(d, resp1.headers); return d; }
203
+ if (resp1.status !== 402) throw new Error('Server error ' + resp1.status + ': ' + (await resp1.text()).substring(0, 200));
204
+
205
+ // Step 2: parse payment requirements
206
+ // FIX v4.16.11: detect V2 by extra.feePayer presence (Dexter sponsorship marker),
207
+ // not by header. Per-tool endpoints (mcp-alpha-scanner, mcp-btc-regime, etc.) only
208
+ // serve 402 in body, no payment-required header. Header check stays as fast path.
209
+ var payReq = null;
210
+ var prHeader = resp1.headers.get('payment-required');
211
+ if (prHeader) {
212
+ try {
213
+ var arr = JSON.parse(Buffer.from(prHeader, 'base64').toString('utf8'));
214
+ if (arr && arr[0]) payReq = arr[0];
215
+ } catch(_e) {}
216
+ }
217
+ if (!payReq) {
218
+ var b402 = await resp1.json();
219
+ if (b402 && b402.accepts && b402.accepts[0]) payReq = b402.accepts[0];
220
+ }
221
+ if (!payReq) throw new Error('No payment requirements in 402');
222
+ // V2 = Dexter sponsored gas = extra.feePayer field present (independent of transport)
223
+ var useV2 = !!(payReq.extra && payReq.extra.feePayer);
224
+
225
+ var amount = parseInt(payReq.maxAmountRequired || payReq.amount || '10000');
226
+ var hasFeePayer = payReq.extra && payReq.extra.feePayer;
227
+ var paymentHeader = '';
228
+ var headerName = '';
229
+
230
+ // Step 3: Try V2 Dexter (gas-sponsored by Dexter — user only needs USDC)
231
+ if (useV2 && hasFeePayer) {
232
+ console.error('[cryptoiz-mcp] V2 mode: Dexter gas-sponsored, paying ' + (amount/1000000).toFixed(4) + ' USDC');
233
+ try {
234
+ var txB64 = await buildV2PaymentPayload(amount, payReq.extra.feePayer);
235
+ // FIX v4.16.10: x402Version:2 (was 1), add 'accepted' (chosen PaymentRequirements
236
+ // verbatim — Dexter /verify needs this to match amount/asset/payTo). Removed bogus
237
+ // signature field — V2 schema only has payload.transaction.
238
+ var v2Payload = {
239
+ x402Version: 2,
240
+ scheme: 'exact',
241
+ network: payReq.network || 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
242
+ accepted: payReq,
243
+ payload: { transaction: txB64 },
244
+ extensions: {}
245
+ };
246
+ paymentHeader = Buffer.from(JSON.stringify(v2Payload)).toString('base64');
247
+ headerName = 'payment-signature';
248
+ } catch(v2Err) {
249
+ console.error('[cryptoiz-mcp] V2 build failed: ' + v2Err.message + ' -> fallback V1');
250
+ useV2 = false;
251
+ }
252
+ }
253
+
254
+ // Step 4: V1 fallback (user pays gas — only if V2 failed)
255
+ if (!paymentHeader) {
256
+ console.error('[cryptoiz-mcp] V1 fallback: direct on-chain transfer');
257
+ var sig = await sendUSDC(amount, toolName);
258
+ paymentHeader = Buffer.from(JSON.stringify({ signature: sig })).toString('base64');
259
+ headerName = 'x-payment';
260
+ }
261
+
262
+ // Step 5: submit payment
263
+ var headers2 = {};
264
+ headers2[headerName] = paymentHeader;
265
+ var resp2 = await fetch(url, { headers: clientHeaders(headers2) });
266
+
267
+ // Step 6: if V2 failed at server, retry with V1
268
+ if (resp2.status !== 200 && useV2) {
269
+ console.error('[cryptoiz-mcp] V2 settle failed, trying V1 fallback...');
270
+ var fallbackSig = await sendUSDC(amount, toolName);
271
+ var v1Header = Buffer.from(JSON.stringify({ signature: fallbackSig })).toString('base64');
272
+ resp2 = await fetch(url, { headers: clientHeaders({ 'x-payment': v1Header }) });
273
+ }
274
+
275
+ if (resp2.status !== 200) throw new Error('Payment failed ' + resp2.status + ': ' + (await resp2.text()).substring(0, 300));
276
+ var data = await resp2.json();
277
+ notifyUpdate(data, resp2.headers);
278
+ return data;
279
+ }
280
+
281
+ var TOOLS = [
282
+ { name: 'get_whale_alpha', description: 'Alpha scanner - early accumulation tokens. Cost: $0.05 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
283
+ { name: 'get_whale_divergence', description: 'Whale divergence signals. Cost: $0.02 USDC', inputSchema: { type: 'object', properties: { timeframe: { type: 'string', enum: ['4h', '1d'] } }, additionalProperties: false } },
284
+ { name: 'get_whale_accumulation', description: 'Accumulation phase tokens. Cost: $0.02 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
285
+ { name: 'get_whale_neutral', description: 'Neutral phase tokens. Cost: $0.02 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
286
+ { name: 'get_whale_distribution', description: 'Distribution phase tokens. Cost: $0.02 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
287
+ { name: 'get_btc_regime', description: 'BTC macro regime. Cost: $0.01 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
288
+ { name: 'get_btc_futures_signal', description: 'BTC futures signal. Cost: $0.03 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
289
+ { name: 'get_token_ca', description: 'Token contract address. FREE', inputSchema: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'], additionalProperties: false } },
290
+ { name: 'get_status', description: 'CryptoIZ MCP status. FREE', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
291
+ ];
292
+
293
+ var server = new Server({ name: 'cryptoiz-mcp', version: VERSION }, { capabilities: { tools: {} } });
294
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
295
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
296
+ try {
297
+ var result = await callTool(request.params.name, request.params.arguments || {});
298
+ return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
299
+ } catch(e) {
300
+ return { content: [{ type: 'text', text: 'Error: ' + e.message }], isError: true };
301
+ }
302
+ });
303
+
304
+ async function main() {
305
+ var transport = new StdioServerTransport();
306
+ await server.connect(transport);
307
+ console.error('[cryptoiz-mcp] ' + VERSION + ' running (V2 Dexter gas-sponsored + V1 fallback)');
308
+ }
309
+ main().catch(console.error);
package/package.json CHANGED
@@ -1,49 +1,50 @@
1
- {
2
- "name": "cryptoiz-mcp",
3
- "version": "4.16.15",
4
- "description": "CryptoIZ MCP Server - Solana DEX whale intelligence (alpha, divergence, accumulation, BTC regime). Recommended install: npx agentcash add https://mcp.cryptoiz.org. x402 V2 + Dexter gas-sponsored payments.",
5
- "main": "index.js",
6
- "type": "commonjs",
7
- "bin": {
8
- "cryptoiz-mcp": "./index.js",
9
- "cryptoiz-mcp-setup": "./setup.js"
10
- },
11
- "files": [
12
- "index.js",
13
- "setup.js",
14
- "package.json",
15
- "README.md"
16
- ],
17
- "dependencies": {
18
- "@modelcontextprotocol/sdk": "^1.29.0",
19
- "@solana/web3.js": "^1.95.8",
20
- "bs58": "^6.0.0"
21
- },
22
- "engines": {
23
- "node": ">=18.0.0"
24
- },
25
- "author": "CryptoIZ",
26
- "license": "MIT",
27
- "repository": {
28
- "type": "git",
29
- "url": "git+https://github.com/dadang11/cryptoiz-mcp.git"
30
- },
31
- "keywords": [
32
- "mcp",
33
- "solana",
34
- "whale-tracking",
35
- "alpha-scanner",
36
- "x402",
37
- "dexter",
38
- "agentcash",
39
- "defi",
40
- "smart-money",
41
- "btc-regime",
42
- "divergence",
43
- "accumulation"
44
- ],
45
- "homepage": "https://cryptoiz.org/McpLanding",
46
- "bugs": {
47
- "url": "https://github.com/dadang11/cryptoiz-mcp/issues"
48
- }
49
- }
1
+ {
2
+ "name": "cryptoiz-mcp",
3
+ "version": "4.16.17",
4
+ "mcpName": "io.github.dadang11/cryptoiz",
5
+ "description": "CryptoIZ MCP Server - Solana DEX whale intelligence (alpha, divergence, accumulation, BTC regime). Recommended install: npx agentcash add https://mcp.cryptoiz.org. x402 V2 + Dexter gas-sponsored payments.",
6
+ "main": "index.js",
7
+ "type": "commonjs",
8
+ "bin": {
9
+ "cryptoiz-mcp": "./index.js",
10
+ "cryptoiz-mcp-setup": "./setup.js"
11
+ },
12
+ "files": [
13
+ "index.js",
14
+ "setup.js",
15
+ "package.json",
16
+ "README.md"
17
+ ],
18
+ "dependencies": {
19
+ "@modelcontextprotocol/sdk": "^1.29.0",
20
+ "@solana/web3.js": "^1.95.8",
21
+ "bs58": "^6.0.0"
22
+ },
23
+ "engines": {
24
+ "node": ">=18.0.0"
25
+ },
26
+ "author": "CryptoIZ",
27
+ "license": "MIT",
28
+ "repository": {
29
+ "type": "git",
30
+ "url": "git+https://github.com/dadang11/cryptoiz-mcp.git"
31
+ },
32
+ "keywords": [
33
+ "mcp",
34
+ "solana",
35
+ "whale-tracking",
36
+ "alpha-scanner",
37
+ "x402",
38
+ "dexter",
39
+ "agentcash",
40
+ "defi",
41
+ "smart-money",
42
+ "btc-regime",
43
+ "divergence",
44
+ "accumulation"
45
+ ],
46
+ "homepage": "https://cryptoiz.org/McpLanding",
47
+ "bugs": {
48
+ "url": "https://github.com/dadang11/cryptoiz-mcp/issues"
49
+ }
50
+ }
package/setup.js CHANGED
@@ -1,51 +1,51 @@
1
- 'use strict';
2
- var VERSION = 'v4.16.15';
3
- var fs = require('fs');
4
- var os = require('os');
5
- var path = require('path');
6
-
7
- var privKey = process.argv[2];
8
- if (!privKey) {
9
- console.log('Usage: npx cryptoiz-mcp-setup YOUR_SOLANA_PRIVATE_KEY');
10
- process.exit(1);
11
- }
12
-
13
- var config = {
14
- mcpServers: {
15
- cryptoiz: {
16
- command: 'C:\\Program Files\\nodejs\\node.exe',
17
- args: [require.resolve('./index.js')],
18
- env: { SVM_PRIVATE_KEY: privKey }
19
- }
20
- }
21
- };
22
-
23
- var configPaths = [
24
- path.join(process.env.LOCALAPPDATA || '', 'Packages', 'Claude_pzs8sxrjxfjjc', 'LocalCache', 'Roaming', 'Claude', 'claude_desktop_config.json'),
25
- path.join(process.env.APPDATA || '', 'Claude', 'claude_desktop_config.json'),
26
- path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
27
- ];
28
-
29
- var written = false;
30
- for (var i = 0; i < configPaths.length; i++) {
31
- var p = configPaths[i];
32
- try {
33
- var dir = path.dirname(p);
34
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
35
- var existing = {};
36
- if (fs.existsSync(p)) {
37
- try { existing = JSON.parse(fs.readFileSync(p, 'utf8')); } catch(_e) {}
38
- }
39
- existing.mcpServers = existing.mcpServers || {};
40
- existing.mcpServers.cryptoiz = config.mcpServers.cryptoiz;
41
- fs.writeFileSync(p, JSON.stringify(existing, null, 2), 'utf8');
42
- console.log('Config written to: ' + p);
43
- written = true;
44
- } catch(_e) {}
45
- }
46
-
47
- if (written) {
48
- console.log('Done! Restart Claude Desktop to activate CryptoIZ MCP.');
49
- } else {
50
- console.log('Could not write config. Please manually add config to Claude Desktop settings.');
51
- }
1
+ 'use strict';
2
+ var VERSION = 'v4.16.15';
3
+ var fs = require('fs');
4
+ var os = require('os');
5
+ var path = require('path');
6
+
7
+ var privKey = process.argv[2];
8
+ if (!privKey) {
9
+ console.log('Usage: npx cryptoiz-mcp-setup YOUR_SOLANA_PRIVATE_KEY');
10
+ process.exit(1);
11
+ }
12
+
13
+ var config = {
14
+ mcpServers: {
15
+ cryptoiz: {
16
+ command: 'C:\\Program Files\\nodejs\\node.exe',
17
+ args: [require.resolve('./index.js')],
18
+ env: { SVM_PRIVATE_KEY: privKey }
19
+ }
20
+ }
21
+ };
22
+
23
+ var configPaths = [
24
+ path.join(process.env.LOCALAPPDATA || '', 'Packages', 'Claude_pzs8sxrjxfjjc', 'LocalCache', 'Roaming', 'Claude', 'claude_desktop_config.json'),
25
+ path.join(process.env.APPDATA || '', 'Claude', 'claude_desktop_config.json'),
26
+ path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
27
+ ];
28
+
29
+ var written = false;
30
+ for (var i = 0; i < configPaths.length; i++) {
31
+ var p = configPaths[i];
32
+ try {
33
+ var dir = path.dirname(p);
34
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
35
+ var existing = {};
36
+ if (fs.existsSync(p)) {
37
+ try { existing = JSON.parse(fs.readFileSync(p, 'utf8')); } catch(_e) {}
38
+ }
39
+ existing.mcpServers = existing.mcpServers || {};
40
+ existing.mcpServers.cryptoiz = config.mcpServers.cryptoiz;
41
+ fs.writeFileSync(p, JSON.stringify(existing, null, 2), 'utf8');
42
+ console.log('Config written to: ' + p);
43
+ written = true;
44
+ } catch(_e) {}
45
+ }
46
+
47
+ if (written) {
48
+ console.log('Done! Restart Claude Desktop to activate CryptoIZ MCP.');
49
+ } else {
50
+ console.log('Could not write config. Please manually add config to Claude Desktop settings.');
51
+ }