cabal-hunter-mcp 0.1.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.dockerignore ADDED
@@ -0,0 +1,4 @@
1
+ node_modules
2
+ .git
3
+ demo
4
+ example_bot.py
package/.mcp.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "mcpServers": {
3
+ "cabal-hunter": {
4
+ "url": "https://api.cabal-hunter.com/mcp",
5
+ "description": "On-chain Solana token cabal detection — traces coordinated wallet funding before you buy"
6
+ }
7
+ }
8
+ }
package/Dockerfile ADDED
@@ -0,0 +1,17 @@
1
+ # Cabal-Hunter local stdio MCP server.
2
+ # Used by Glama (and any MCP host) to build + run the server for automated
3
+ # tool discovery and quality checks. Requires no secrets — the free tier works
4
+ # out of the box; paid scans use x402 at call time.
5
+ FROM node:20-slim
6
+
7
+ WORKDIR /app
8
+
9
+ # Install deps first for layer caching.
10
+ COPY package.json ./
11
+ RUN npm install --omit=dev --no-audit --no-fund
12
+
13
+ # Copy the server.
14
+ COPY server ./server
15
+
16
+ # MCP servers speak JSON-RPC over stdio.
17
+ ENTRYPOINT ["node", "server/index.mjs"]
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 Cabal-Hunter
3
+ Copyright (c) 2026 Cabal-Hunter (paulf280-ui)
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,95 +1,439 @@
1
- # cabal-hunter-mcp
1
+ # Solana Safe Sniper — MCP Template
2
2
 
3
- **On-chain Solana cabal & rug detection as an MCP server.** One tool — `check_cabal_risk` — scans any Solana token mint *before your agent buys* and returns an **Exit-Liquidity Risk** verdict (`SAFE | REVIEW | AVOID`), a 0–100 cabal score, funding-cluster detection, same-block Jito-bundle detection, coordinated-dump detection, serial-rug **deployer history** ("launched 14, 13 dead"), and a Solana-native **honeypot** check (freeze authority + Token-2022 traps). Every flag links to its on-chain evidence transaction.
4
-
5
- [![npm](https://img.shields.io/npm/v/cabal-hunter-mcp?color=cb3837&logo=npm)](https://www.npmjs.com/package/cabal-hunter-mcp)
6
3
  [![MCP server](https://img.shields.io/badge/MCP-server-7c3aed)](https://api.cabal-hunter.com/mcp)
7
4
  [![Solana](https://img.shields.io/badge/Solana-on--chain-14F195)](https://api.cabal-hunter.com)
8
- [![Free tier](https://img.shields.io/badge/250%2Fmo%20free-no%20API%20key-10b981)](https://api.cabal-hunter.com/api/info)
5
+ [![Live demo](https://img.shields.io/badge/%E2%96%B6%20live-holder%20map-2dd4bf)](https://api.cabal-hunter.com/demo)
6
+ [![Free tier](https://img.shields.io/badge/250%2Fmo%20free-then%20%240.001-ff4d6d)](https://api.cabal-hunter.com/api/info)
7
+ [![Install MCP in VS Code](https://img.shields.io/badge/VS_Code-One--click_MCP_install-0098FF?logo=githubcopilot&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=cabal-hunter&config=%7B%22type%22%3A%20%22http%22%2C%20%22url%22%3A%20%22https%3A%2F%2Fapi.cabal-hunter.com%2Fmcp%22%7D)
8
+ [![Install MCP in Cursor](https://img.shields.io/badge/Cursor-One--click_MCP_install-111111)](https://cursor.com/install-mcp?name=cabal-hunter&config=eyJ1cmwiOiAiaHR0cHM6Ly9hcGkuY2FiYWwtaHVudGVyLmNvbS9tY3AifQ==)
9
+ [![ElizaOS plugin](https://img.shields.io/badge/ElizaOS-plugin--cabal--hunter-7c3aed)](https://github.com/paulf280-ui/plugin-cabal-hunter)
9
10
  [![License: MIT](https://img.shields.io/badge/license-MIT-94a3b8)](LICENSE)
10
11
 
11
- Contract-clean is **not** cabal-clean. RugCheck-style scanners tell you the mint/freeze/LP are fine — they don't tell you that 15 wallets funded from one source are holding 30% of supply, waiting to dump on you. That's what this catches.
12
+ > 🌐 **Available in 9 languages:** [English](https://api.cabal-hunter.com/) · [Español](https://api.cabal-hunter.com/es) · [Português](https://api.cabal-hunter.com/pt) · [Français](https://api.cabal-hunter.com/fr) · [Deutsch](https://api.cabal-hunter.com/de) · [Nederlands](https://api.cabal-hunter.com/nl) · [中文](https://api.cabal-hunter.com/zh) · [日本語](https://api.cabal-hunter.com/ja) · [한국어](https://api.cabal-hunter.com/ko)
12
13
 
13
- ## Quick start
14
+ ![Cabal-Hunter — live Solana cabal and rug analysis: interactive 3D holder map, serial-launcher deployer history, and an Exit-Liquidity Risk verdict](demo/screenshot.png)
14
15
 
15
- ```bash
16
- npx cabal-hunter-mcp
16
+ > Stop your AI trading agents getting rugged by coordinated wallet cabals.
17
+ > Drop-in template for Claude Code, Cursor, and ElizaOS.
18
+
19
+ **▶ Try it now: [live 3D holder map of any Solana token →](https://api.cabal-hunter.com/demo)** — no signup.
20
+
21
+ **Cabal-Hunter is a free on-chain Solana token safety scanner and rug checker.** It detects coordinated wallet cabals, same-block Jito bundle buys, serial-launcher deployers and coordinated dumps on any Solana mint (pump.fun, PumpSwap, Raydium) — and answers the one question that matters before you ape: *are you the exit liquidity?* Use it via **MCP** (Claude, Cursor, ElizaOS), a **REST API**, or a free **interactive 3D holder map**.
22
+
23
+ ---
24
+
25
+ ## The Problem
26
+
27
+ Your autonomous trading agent is reading rug.check scores, liquidity locks, and contract audits.
28
+
29
+ **None of that catches a cabal.**
30
+
31
+ A cabal is 15 fresh wallets — all funded from the same master wallet, all buying in the first 90 seconds of launch — quietly accumulating 25-40% of supply before your bot sees the first candle. Contract clean. LP burned. Everything green.
32
+
33
+ Then they dump. Simultaneously. Into your liquidity.
34
+
35
+ This template integrates **[Cabal-Hunter](https://api.cabal-hunter.com)** — a live on-chain funding tracer — as a pre-trade safety check so your agent catches coordinated launches before it signs a swap.
36
+
37
+ ---
38
+
39
+ ## The one question it answers: are YOU the exit liquidity?
40
+
41
+ The classic pump.fun exit-liquidity setup: wallets positioned before the crowd take the bottom of a launch, then dump on the retail (and bots) that pile in after. Cabal-Hunter's headline output is a single **Exit-Liquidity Risk** verdict (`LOW | ELEVATED | HIGH`) that synthesises every signal below into the only thing that matters before you sign a swap: *are the insiders positioned to dump on you?*
42
+
43
+ ## What Cabal-Hunter Does — Seven Detection Layers
44
+
45
+ ```
46
+ Token mint address
47
+ ↓
48
+ 0. EXIT-LIQUIDITY RISK — the headline verdict. Synthesises the layers
49
+ below (bundle, concentration, shared funder, coordinated dump, serial-
50
+ rug dev) into LOW | ELEVATED | HIGH: are insiders set up to dump on
51
+ a buyer? The one number a trading agent needs.
52
+ ↓
53
+ 1. FUNDING TRACE — top holders walked back to launch: who was funded
54
+ by the same source wallet? (classic cabal signature). Every cluster
55
+ carries evidence_txs[] — the actual funding transactions on Solscan.
56
+ ↓
57
+ 2. SAME-BLOCK BUNDLE DETECTION — holders whose token accounts were
58
+ created in the EXACT same slot bought in one Jito bundle. Catches
59
+ stealth launches that route funding through intermediaries to
60
+ evade layer 1. Returned as `time_sync: true`.
61
+ ↓
62
+ 3. COORDINATED DUMP DETECTION — ≥2 holders that SOLD a meaningful chunk
63
+ (≥25% of their bag each) in the EXACT same block — a cabal exiting in
64
+ real time. `coordinated_exit: true`, with sold_pct = % of supply
65
+ dumped and the sell transactions linked. Same-slot + meaningful-size +
66
+ distinct wallets = near-zero false positives.
67
+ ↓
68
+ 4. DEV TRACK RECORD — the creator wallet is resolved on-chain (bonding
69
+ curve pre-graduation, pump-amm pool after — works on any age token),
70
+ and their full launch history is pulled WITH THE PEAK MARKET CAP each
71
+ past token hit. A dead-count alone hides a pump-and-dump: a dev whose
72
+ tokens all died at $4k is a nobody, but one who ran a token to $728k
73
+ then dumped it to dust has done it to holders before. Reputation:
74
+ SERIAL_RUGGER | DEAD_ON_ARRIVAL | MIXED | PROVEN, with per-launch
75
+ peak → now (paid tier returns the full launches[] array).
76
+ ↓
77
+ 5. CEX-NOISE FILTER — holders funded from a shared exchange or
78
+ high-volume infra wallet are NOT a cabal. They're excluded from the
79
+ score and surfaced transparently in filtered_clusters[], so you never
80
+ get a false positive from people who just withdrew from Binance.
81
+ ↓
82
+ 6. HONEYPOT CHECK (Solana-native) — one RPC read of the mint account:
83
+ is the FREEZE authority live (issuer can freeze your tokens — the
84
+ sell-block lever)? is the MINT authority live (supply can be
85
+ inflated)? any Token-2022 traps (transfer fees up to 100%, transfer
86
+ hooks that block sells, permanent-delegate clawback)? On Solana a
87
+ "honeypot" is built from these — tokens have no per-token contract
88
+ code to audit. Returns `honeypot_risk: LOW | HIGH` +
89
+ `freeze_authority_revoked` / `mint_authority_revoked` /
90
+ `token2022_risks[]`.
91
+ ↓
92
+ Returns: Cabal Score (0-100) + cluster map + deployer verdict
93
+ + honeypot verdict + on-chain receipts + hard verdict
17
94
  ```
18
95
 
19
- No install, no signup, no API key — **250 free scans/month per IP**. That's the whole setup; the command below is what you drop into any MCP client.
96
+ The deployer layer is the one cabals can't dodge: **wallets rotate, deployers leave a paper trail.** A response of `"deployer": {"reputation": "SERIAL_RUGGER", "tokens_launched": 22, "best_peak_usd": 728432, "pump_and_dumps": 2}` shows the dev's full track record before the first candle — including whether this "dead" dev has quietly run tokens to six figures and dumped them on holders before. (Honest context: most prolific pump.fun creators have high dead-token rates, so this signal is capped — it flags a token for review but never drives a HIGH verdict on its own.)
20
97
 
21
- ### Claude Desktop / Claude Code / Cursor / VS Code / ElizaOS
98
+ **Receipts, not magic.** Every cluster and red flag links to the underlying Solscan transaction (`evidence_txs[]`, `holders[].funding_tx`) — verify the trail yourself instead of trusting a score.
99
+
100
+ **Response in <100ms** on pre-indexed tokens — every pump.fun graduation is scanned and cached automatically as it happens.
101
+
102
+ **Free tier: 250 scans/month per IP.** Then $0.001 USDC per scan — priced at cost (it covers the Helius RPC calls behind each live on-chain trace), paid natively on Solana. No account. No API key. No subscription.
103
+
104
+ ---
105
+
106
+ ## Quick Start
107
+
108
+ ### 1. Claude Code / Claude Desktop
109
+
110
+ Add to your MCP config (`~/.claude/mcp.json` or project `.mcp.json`):
22
111
 
23
112
  ```json
24
113
  {
25
114
  "mcpServers": {
26
115
  "cabal-hunter": {
27
- "command": "npx",
28
- "args": ["-y", "cabal-hunter-mcp"]
116
+ "url": "https://api.cabal-hunter.com/mcp"
29
117
  }
30
118
  }
31
119
  }
32
120
  ```
33
121
 
34
- Prefer a remote HTTP server (no local process)? Point straight at the hosted endpoint instead:
122
+ That's it. Claude will now call `check_cabal_risk` automatically when you ask it to analyse a Solana token.
123
+
124
+ **Example prompt:**
125
+ > "Before we buy into this token, check if there are any coordinated wallets: `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`"
126
+
127
+ Claude calls the tool, pays $0.001 USDC from your connected wallet, and returns the full analysis.
128
+
129
+ ---
130
+
131
+ ### 2. Cursor
132
+
133
+ Add to `.cursor/mcp.json` in your project root:
35
134
 
36
135
  ```json
37
- { "mcpServers": { "cabal-hunter": { "url": "https://api.cabal-hunter.com/mcp" } } }
136
+ {
137
+ "mcpServers": {
138
+ "cabal-hunter": {
139
+ "url": "https://api.cabal-hunter.com/mcp"
140
+ }
141
+ }
142
+ }
143
+ ```
144
+
145
+ ---
146
+
147
+ ### 3. ElizaOS (with automatic x402 payment)
148
+
149
+ If you're using ElizaOS with `@hugen/plugin-x402-solana`, payment is handled automatically. Add to your agent config:
150
+
151
+ ```json
152
+ {
153
+ "plugins": ["@hugen/plugin-x402-solana"],
154
+ "mcpServers": {
155
+ "cabal-hunter": {
156
+ "url": "https://api.cabal-hunter.com/mcp"
157
+ }
158
+ }
159
+ }
160
+ ```
161
+
162
+ Your agent will call `check_cabal_risk(mintAddress)` before any swap and abort if `cabalScore >= 35` or `isControlled === true`.
163
+
164
+ ---
165
+
166
+ ### 4. Direct REST API
167
+
168
+ For headless scripts, custom bots, or any language. **The first 100 calls/month are free — no key, no signup.** Just call it:
169
+
170
+ ```bash
171
+ curl "https://api.cabal-hunter.com/api/scan-cabal?mintAddress=YOUR_MINT_ADDRESS"
172
+ ```
173
+
174
+ You get the full analysis back immediately, with `free_queries_remaining` so you always know where you stand. Machine-readable contract: [`/openapi.json`](https://api.cabal-hunter.com/openapi.json).
175
+
176
+ Once the free tier is used up, calls are $0.001 USDC via x402 — your agent just pays, no billing setup:
177
+
178
+ **Step 1 — Request analysis (get payment instructions):**
179
+ ```bash
180
+ curl -X POST https://api.cabal-hunter.com/api/scan-cabal \
181
+ -H "Content-Type: application/json" \
182
+ -d '{"mintAddress": "YOUR_MINT_ADDRESS"}'
38
183
  ```
39
184
 
40
- ## The tool
185
+ Response (HTTP 402):
186
+ ```json
187
+ {
188
+ "error": "payment_required",
189
+ "payment": {
190
+ "recipient": "ATYjZ1kWoHWhj74umGJ8wFqUeW1yeSGBbLi1UQpahPxt",
191
+ "amount_usdc": 0.001,
192
+ "memo_required": "ch-xxxx-xxxx-xxxx",
193
+ "instructions": "Send 0.001 USDC with this memo, then resubmit with X-Payment-Signature header"
194
+ }
195
+ }
196
+ ```
41
197
 
42
- **`check_cabal_risk({ mint })`** — pass a Solana token mint (contract) address. Returns the full forensic JSON:
198
+ **Step 2 — Pay & resubmit:**
199
+ ```bash
200
+ curl -X POST https://api.cabal-hunter.com/api/scan-cabal \
201
+ -H "Content-Type: application/json" \
202
+ -H "X-Payment-Signature: YOUR_TX_SIGNATURE" \
203
+ -d '{"mintAddress": "YOUR_MINT_ADDRESS"}'
204
+ ```
43
205
 
44
- ```jsonc
206
+ **Response (HTTP 200):**
207
+ ```json
45
208
  {
46
- "recommendation": "AVOID", // SAFE | REVIEW | AVOID ← the headline
47
- "risk": "HIGH", // exit-liquidity risk
48
- "cabal_score": 100, // 0-100
49
- "honeypot_risk": "LOW", // freeze authority + Token-2022 traps
50
- "mint_authority_revoked": true,
51
- "freeze_authority_revoked": true,
52
- "deployer": { "verdict": "SERIAL_RUGGER", "tokens_launched": 14, "dead": 13 },
209
+ "mint": "YOUR_MINT",
210
+ "token_name": "EXAMPLE",
211
+ "risk": "HIGH",
212
+ "cabal_score": 72.4,
213
+ "is_controlled": true,
214
+ "time_sync": true,
215
+ "verdict": "AVOID — 4 wallets bought in the EXACT same block (bundled launch), controlling 34.1% of supply. DEPLOYER ALERT: this creator has launched 14 tokens, 13 of 13 checked are dead (100%).",
53
216
  "coordinated_clusters": [
54
- { "wallets": 5, "combined_pct": 23.1, "evidence_tx": "https://solscan.io/tx/…" }
217
+ {
218
+ "type": "funding",
219
+ "master_full": "FvbEKF...9RUg",
220
+ "master_short": "FvbEKF…9RUg",
221
+ "wallet_count": 4,
222
+ "combined_pct": 34.1,
223
+ "risk": "HIGH",
224
+ "evidence_txs": ["4Y8auc5G...", "2XQx9LFv...", "AAbJ7rej..."]
225
+ }
55
226
  ],
56
- "time_sync": true, // same-block (Jito-bundled) buys
57
- "coordinated_exit": false, // ≥2 holders dumped together
58
- "top_reasons": ["..."],
59
- "wallets_checked": 15,
60
- "scan_complete": true
227
+ "filtered_clusters": [
228
+ {
229
+ "funder_label": "high-volume wallet",
230
+ "master_short": "43ViqZ…Z6iy",
231
+ "wallet_count": 2,
232
+ "combined_pct": 4.4
233
+ }
234
+ ],
235
+ "deployer": {
236
+ "creator": "5TbRN6...full address...",
237
+ "creator_short": "5TbRN6…2TGC",
238
+ "tokens_launched": 14,
239
+ "dead": 13,
240
+ "sampled": 13,
241
+ "dead_pct": 100.0,
242
+ "verdict": "SERIAL_LAUNCHER"
243
+ },
244
+ "holders": [
245
+ { "rank": 1, "address": "...", "pct": 12.4, "cluster_id": 0, "funding_tx": "4Y8auc5G..." }
246
+ ],
247
+ "wallets_checked": 12,
248
+ "analysis_time_ms": 487,
249
+ "source": "real_time"
250
+ }
251
+ ```
252
+
253
+ ### 5. Run the MCP server locally (Docker / Node)
254
+
255
+ **Fastest — no clone needed:** `npx cabal-hunter-mcp` — the same stdio server, published to npm ([cabal-hunter-mcp](https://github.com/paulf280-ui/cabal-hunter-mcp) · [npm](https://www.npmjs.com/package/cabal-hunter-mcp)). Or run it from this repo:
256
+
257
+ Prefer to run the connector yourself instead of hitting the hosted `/mcp`
258
+ endpoint? This repo ships a thin **stdio MCP server** that exposes
259
+ `check_cabal_risk(mintAddress)` and proxies to the Cabal-Hunter API (free tier
260
+ works with no key; paid scans use x402 at call time):
261
+
262
+ ```bash
263
+ # Node 18+
264
+ npm install
265
+ node server/index.mjs
266
+
267
+ # or Docker
268
+ docker build -t cabal-hunter-mcp .
269
+ docker run -i cabal-hunter-mcp
270
+ ```
271
+
272
+ Then point any MCP client at the local command:
273
+
274
+ ```json
275
+ {
276
+ "mcpServers": {
277
+ "cabal-hunter": {
278
+ "command": "node",
279
+ "args": ["server/index.mjs"]
280
+ }
281
+ }
61
282
  }
62
283
  ```
63
284
 
64
- `scan_complete` / `wallets_checked` are included on purpose so your agent can apply **its own** risk tolerance instead of inheriting ours — the score is a starting point you can verify (every cluster carries an `evidence_tx`), not a verdict you take on faith.
285
+ ---
286
+
287
+ ## Integrate into Your Trading Logic
288
+
289
+ ```python
290
+ import requests
291
+
292
+ def is_safe_to_buy(mint_address: str, payment_sig: str) -> bool:
293
+ """Returns True if token passes cabal check."""
294
+ resp = requests.post(
295
+ "https://api.cabal-hunter.com/api/scan-cabal",
296
+ json={"mintAddress": mint_address},
297
+ headers={"X-Payment-Signature": payment_sig}
298
+ )
299
+ if resp.status_code != 200:
300
+ return False # fail-safe: don't buy on error
301
+ data = resp.json()
302
+ # Block on: coordinated control, high score, bundled launch,
303
+ # or a deployer with a history of dead tokens
304
+ deployer_verdict = (data.get("deployer") or {}).get("verdict", "UNKNOWN")
305
+ return (
306
+ not data.get("is_controlled")
307
+ and data.get("cabal_score", 100) < 35
308
+ and not data.get("time_sync")
309
+ and deployer_verdict not in ("SERIAL_RUGGER", "SERIAL_LAUNCHER", "POOR_TRACK_RECORD")
310
+ )
311
+
312
+ # In your bot's buy logic:
313
+ if is_safe_to_buy(token_mint, my_payment_sig):
314
+ execute_swap(token_mint, sol_amount)
315
+ else:
316
+ print(f"Cabal detected — skipping {token_mint}")
317
+ ```
318
+
319
+ ---
320
+
321
+ ## Interactive 3D Holder Map (Free)
322
+
323
+ See exactly what the analysis found. Every real holder is a faceted crystal sized by its share of supply; wallets in the same cluster are joined by light beams, and the liquidity pool and locked supply sit apart in a wireframe vault because they cannot be sold. Drag to rotate, hover for the wallet, click through to Solscan:
324
+
325
+ ```
326
+ https://api.cabal-hunter.com/map?mint=ANY_SOLANA_MINT
327
+ ```
328
+
329
+ Free to view, in 9 languages. Share this URL when you catch a rug. Every crystal is clickable and links to Solscan for deep-dive research.
330
+
331
+ ---
332
+
333
+ ## Cabal-Hunter everywhere
334
+
335
+ Same detection engine, wherever your stack lives:
65
336
 
66
- ### Gate a buy in your agent
337
+ - **`npx cabal-hunter-mcp`** — standalone MCP server for Claude · Cursor · VS Code · any MCP client: [cabal-hunter-mcp](https://github.com/paulf280-ui/cabal-hunter-mcp) · [npm](https://www.npmjs.com/package/cabal-hunter-mcp)
338
+ - **ElizaOS plugin:** `npm i elizaos-plugin-cabal-hunter` — [plugin-cabal-hunter](https://github.com/paulf280-ui/plugin-cabal-hunter) · [npm](https://www.npmjs.com/package/elizaos-plugin-cabal-hunter)
339
+ - **REST API + OpenAPI:** [api.cabal-hunter.com](https://api.cabal-hunter.com) · [/openapi.json](https://api.cabal-hunter.com/openapi.json)
67
340
 
68
- > "Before buying any token, call `check_cabal_risk` with the mint. If `recommendation` is `AVOID` or `cabal_score >= 65` or `honeypot_risk` is `HIGH`, skip the trade and say why."
341
+ ---
69
342
 
70
343
  ## Pricing
71
344
 
72
- - **250 scans/month per IP — free, no key.**
73
- - After that: **$9/month for Unlimited** (fair use), or pay-as-you-go at **$0.001 USDC per scan** (priced at cost). No signup, no card.
74
- - Prepaid key: send USDC, `POST /api/buy-key`, then set `CABAL_HUNTER_API_KEY` (sent as the `X-API-Key` header). Full details: [api.cabal-hunter.com/pricing](https://api.cabal-hunter.com/pricing).
345
+ **First 250 scans every month are free** — per IP, no signup, no API key.
346
+
347
+ After that, pick whatever matches how hard your bot works (priced at cost — it covers the Helius RPC behind each live on-chain trace):
348
+
349
+ | Plan | Price | What you get |
350
+ |------|-------|--------------|
351
+ | **Unlimited** ⭐ | $9 USDC / month | Scan all you want — _fair use: 50,000/mo, more than any bot needs_ |
352
+ | **Pay as you go** | $0.001 USDC / scan | Only what you use — prepaid or per-call, no commitment |
353
+
354
+ Prepaid keys: send USDC once → `POST /api/buy-key` with the tx signature → use header `X-API-Key` on every scan. Or pay per-call via x402 (`X-Payment-Signature` header). No credit card, no account, no lock-in.
355
+
356
+ **Does it pay for itself?** A bot sniping $1 positions loses ~$40/month to rugs it never saw coming — rugs are the #1 way snipers bleed money. Cabal-Hunter flags them _before_ the buy. Dodge just 9 and the Unlimited tier has already paid for itself; every rug after that is capital back in your pocket, redeployed into trades that can actually run.
357
+
358
+ Payment is native on Solana — no credit card, no account, no subscription lock-in.
359
+
360
+ ---
361
+
362
+ ## Live dashboard badge
363
+
364
+ Drop a live safety badge into your own bot's dashboard — two lines of HTML, and every token shows its verdict as it trades:
365
+
366
+ ```html
367
+ <div class="cabal-hunter-badge" data-mint="YOUR_TOKEN_MINT"></div>
368
+ <script src="https://api.cabal-hunter.com/widget.js" defer></script>
369
+ ```
370
+
371
+ It renders the 0–100 score, the plain-English verdict, and the active flags (bundled launch, coordinated dump, whale concentration, serial-launcher deployer, honeypot). Add `data-refresh="120"` to re-scan live as you trade, and `data-api-key="..."` once you're past your free scans. Works anywhere — React, plain HTML, any site.
372
+
373
+ ---
374
+
375
+ ## API Reference
75
376
 
76
- ## Configuration
377
+ | Endpoint | Description | Auth |
378
+ |----------|-------------|------|
379
+ | `POST /api/scan-cabal` | Full cabal analysis | $0.001 USDC |
380
+ | `GET /api/scan-cabal?mintAddress=` | GET version | $0.001 USDC |
381
+ | `GET /map?mint=` | Interactive 3D holder map | Free |
382
+ | `GET /api/cex-funding?mint=` | Per-exchange funding breakdown (which CEXes funded holders, % each) | Free |
383
+ | `GET /api/trade-analysis?mint=` | Cohort PnL (Team/Snipers/Insiders) + wash-trading score + exit-liquidity price impact, one call | Free |
384
+ | `POST /api/watch` | Register an emergency dump webhook for a mint (push on dump/rug start) | Free |
385
+ | `GET /api/info` | Pricing, endpoints | Free |
77
386
 
78
- | Env var | Default | Purpose |
79
- |---|---|---|
80
- | `CABAL_HUNTER_API_KEY` | *(none)* | Prepaid key for unlimited / metered use (`X-API-Key`). |
81
- | `CABAL_HUNTER_API` | `https://api.cabal-hunter.com` | Override the API base URL. |
387
+ ### Emergency dump webhook (auto-exit)
82
388
 
83
- ## Other ways to use Cabal-Hunter
389
+ Instead of polling, let your bot subscribe to a token it holds — we push the moment a coordinated dump or liquidity drain starts:
84
390
 
85
- - **REST:** `curl "https://api.cabal-hunter.com/api/scan-cabal?mintAddress=<MINT>"` — [OpenAPI spec](https://api.cabal-hunter.com/openapi.json)
86
- - **ElizaOS plugin:** [`elizaos-plugin-cabal-hunter`](https://github.com/paulf280-ui/plugin-cabal-hunter) (`npm install elizaos-plugin-cabal-hunter`)
87
- - **Human?** Free interactive bubble map — wallets, Solscan receipts, live chart + trade links on one screen: [api.cabal-hunter.com/map](https://api.cabal-hunter.com/map)
391
+ ```bash
392
+ curl -X POST https://api.cabal-hunter.com/api/watch \
393
+ -H "Content-Type: application/json" \
394
+ -d '{"mint":"YOUR_MINT","webhook_url":"https://your-bot.com/dump-alert"}'
395
+ ```
396
+
397
+ Your endpoint receives:
398
+ ```json
399
+ { "event":"dump_detected", "mint":"...", "reason":"price −34% since last check",
400
+ "coordinated": true, "price_usd": 0.0001, "liquidity_usd": 4200,
401
+ "action":"consider_immediate_exit", "ts": 1781370000 }
402
+ ```
403
+ | `GET /health` | Uptime check | Free |
404
+ | `POST /mcp` | MCP tool endpoint | $0.001 USDC per call |
405
+
406
+ ---
407
+
408
+ ## Infrastructure
409
+
410
+ - **RPC**: Dedicated Helius node (Frankfurt) — fastest Solana data available
411
+ - **Hosting**: AWS EC2 Frankfurt — low latency for EU/global
412
+ - **Analysis**: Real on-chain data — no scrapers, no caches of cached caches
413
+ - **Uptime**: 99.9% target — monitored, auto-restart via systemd
414
+
415
+ ---
416
+
417
+ ## FAQ
418
+
419
+ **What is a Solana cabal?**
420
+ A group of wallets — often funded from the same source and buying in the same block — that quietly accumulate a large share of a token's supply before retail, then dump simultaneously into everyone who buys after launch.
421
+
422
+ **How do I check if a Solana token is a rug?**
423
+ Scan the mint with Cabal-Hunter (MCP, REST API, or the free 3D holder map). It traces holder funding back to shared sources, detects same-block bundle buys, flags serial-launcher deployers and live coordinated dumps, and returns an **Exit-Liquidity Risk** verdict: `LOW`, `ELEVATED`, or `HIGH`.
424
+
425
+ **Is it free?**
426
+ Yes — 250 scans/month per IP, with no signup or API key. Beyond that it's $0.001 USDC per scan — which just covers the Helius RPC cost of the live trace — paid natively on Solana.
427
+
428
+ **Can AI trading agents use it?**
429
+ Yes — that's the whole point. The MCP server (`api.cabal-hunter.com/mcp`) lets Claude, Cursor and ElizaOS agents call `check_cabal_risk(mintAddress)` automatically before any swap, and a REST API covers any other language.
430
+
431
+ ---
88
432
 
89
- ## What it detects (why "contract-clean" misses it)
433
+ ## License
90
434
 
91
- A cabal is 15 fresh wallets — all funded from the same master wallet, all buying in the first seconds of launch — quietly accumulating 25–40% of supply before your bot sees the first candle. Contract clean. LP burned. Everything green. Then they dump, simultaneously, into your liquidity. Cabal-Hunter traces the funding graph on-chain and answers the only question that matters before you sign a swap: **are you the exit liquidity?**
435
+ MIT — fork it, build on it, integrate it. If you build something with this, share it.
92
436
 
93
437
  ---
94
438
 
95
- MIT licensed. Powered by [Cabal-Hunter](https://api.cabal-hunter.com). This package is a thin MCP wrapper over the hosted API — the detection runs server-side against live Solana on-chain data (Helius RPC).
439
+ *Built by [PF Capital](https://api.cabal-hunter.com) · Powered by Helius · Contact: api.cabal-hunter.com/api/info*
@@ -0,0 +1,72 @@
1
+ """
2
+ Cabal-Hunter API demo — Python
3
+ Checks a Solana token for coordinated wallet clusters before buying.
4
+
5
+ First 100 queries/month are FREE — no payment required.
6
+ After that: $0.05 USDC per query via X-Payment-Signature header.
7
+
8
+ Run: python demo/python_demo.py
9
+ """
10
+
11
+ import requests
12
+ import json
13
+
14
+ API = "https://api.cabal-hunter.com/api/scan-cabal"
15
+
16
+ # Demo token — known cabal detected
17
+ DEMO_MINT = "Axpzs7FEMYzpcfqVcDjDMQb2rsgMYVJADNpUZe7bpump"
18
+
19
+
20
+ def check_token(mint: str) -> dict:
21
+ """
22
+ Query Cabal-Hunter for a token.
23
+ Free for first 100 queries/month. After that, pass X-Payment-Signature.
24
+ """
25
+ resp = requests.post(API, json={"mintAddress": mint}, timeout=30)
26
+
27
+ if resp.status_code == 200:
28
+ return resp.json()
29
+
30
+ if resp.status_code == 402:
31
+ data = resp.json()
32
+ print("\n💳 Free quota exhausted. Payment required:")
33
+ print(f" Send {data['payment']['amount_usdc']} USDC to {data['payment']['recipient']}")
34
+ print(f" Memo: {data['payment']['memo_required']}")
35
+ print(f" Then re-submit with: X-Payment-Signature: <your_tx_sig>")
36
+ return {}
37
+
38
+ raise RuntimeError(f"Unexpected {resp.status_code}: {resp.text}")
39
+
40
+
41
+ def is_safe(report: dict) -> bool:
42
+ """Returns True if the token passes the cabal check."""
43
+ if not report:
44
+ return False # fail-safe: treat no-response as unsafe
45
+ return not report.get("is_controlled") and report.get("cabal_score", 100) < 35
46
+
47
+
48
+ if __name__ == "__main__":
49
+ print(f"Checking {DEMO_MINT[:8]}…\n")
50
+
51
+ report = check_token(DEMO_MINT)
52
+ if not report:
53
+ exit(1)
54
+
55
+ free_left = report.get("free_queries_remaining")
56
+ if free_left is not None:
57
+ print(f"✅ Free tier — {free_left} free queries remaining this month\n")
58
+
59
+ print(f"Token: {report.get('token_name', '?')}")
60
+ print(f"Risk: {report.get('risk')}")
61
+ print(f"Cabal Score: {report.get('cabal_score')}/100")
62
+ print(f"Verdict: {report.get('verdict')}")
63
+ print(f"Analysis: {report.get('analysis_time_ms')}ms ({report.get('source')})")
64
+
65
+ clusters = report.get("coordinated_clusters", [])
66
+ if clusters:
67
+ print(f"\n⚠️ {len(clusters)} cluster(s) detected:")
68
+ for c in clusters:
69
+ print(f" {c['wallet_count']} wallets from {c['master_short']} — {c['combined_pct']}% supply [{c['risk']}]")
70
+
71
+ print(f"\n{'🚫 SKIP — cabal detected' if not is_safe(report) else '✅ SAFE — no cabal detected'}")
72
+ print(f"\nVisual map: https://api.cabal-hunter.com/map?mint={DEMO_MINT}")
Binary file
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Cabal-Hunter API demo — TypeScript/Node.js
3
+ * Checks a Solana token for coordinated wallet clusters before buying.
4
+ *
5
+ * First 100 queries/month are FREE — no payment required.
6
+ * After that: $0.05 USDC per query via X-Payment-Signature header.
7
+ *
8
+ * Run: npx tsx demo/typescript_demo.ts
9
+ */
10
+
11
+ const API = "https://api.cabal-hunter.com/api/scan-cabal"
12
+
13
+ // Demo token — known cabal detected
14
+ const DEMO_MINT = "Axpzs7FEMYzpcfqVcDjDMQb2rsgMYVJADNpUZe7bpump"
15
+
16
+ interface CabalReport {
17
+ token_name: string
18
+ risk: "HIGH" | "MEDIUM" | "CLEAN"
19
+ cabal_score: number
20
+ is_controlled: boolean
21
+ verdict: string
22
+ coordinated_clusters: Array<{
23
+ master_short: string
24
+ wallet_count: number
25
+ combined_pct: number
26
+ risk: string
27
+ }>
28
+ wallets_checked: number
29
+ analysis_time_ms: number
30
+ source: string
31
+ free_queries_remaining?: number
32
+ }
33
+
34
+ async function checkToken(mint: string, paymentSig?: string): Promise<CabalReport | null> {
35
+ const headers: Record<string, string> = { "Content-Type": "application/json" }
36
+ if (paymentSig) headers["X-Payment-Signature"] = paymentSig
37
+
38
+ const resp = await fetch(API, {
39
+ method: "POST",
40
+ headers,
41
+ body: JSON.stringify({ mintAddress: mint }),
42
+ })
43
+
44
+ if (resp.status === 200) return resp.json() as Promise<CabalReport>
45
+
46
+ if (resp.status === 402) {
47
+ const data = await resp.json() as { payment: { amount_usdc: number; recipient: string; memo_required: string } }
48
+ console.log("\n💳 Free quota exhausted. Payment required:")
49
+ console.log(` Send ${data.payment.amount_usdc} USDC to ${data.payment.recipient}`)
50
+ console.log(` Memo: ${data.payment.memo_required}`)
51
+ console.log(` Then re-submit with: X-Payment-Signature: <your_tx_sig>`)
52
+ return null
53
+ }
54
+
55
+ throw new Error(`Unexpected ${resp.status}: ${await resp.text()}`)
56
+ }
57
+
58
+ function isSafe(report: CabalReport): boolean {
59
+ return !report.is_controlled && report.cabal_score < 35
60
+ }
61
+
62
+ async function main() {
63
+ console.log(`Checking ${DEMO_MINT.slice(0, 8)}…\n`)
64
+
65
+ const report = await checkToken(DEMO_MINT)
66
+ if (!report) process.exit(1)
67
+
68
+ if (report.free_queries_remaining !== undefined) {
69
+ console.log(`✅ Free tier — ${report.free_queries_remaining} free queries remaining this month\n`)
70
+ }
71
+
72
+ console.log(`Token: ${report.token_name}`)
73
+ console.log(`Risk: ${report.risk}`)
74
+ console.log(`Cabal Score: ${report.cabal_score}/100`)
75
+ console.log(`Verdict: ${report.verdict}`)
76
+ console.log(`Analysis: ${report.analysis_time_ms}ms (${report.source})`)
77
+
78
+ if (report.coordinated_clusters.length > 0) {
79
+ console.log(`\n⚠️ ${report.coordinated_clusters.length} cluster(s) detected:`)
80
+ for (const c of report.coordinated_clusters) {
81
+ console.log(` ${c.wallet_count} wallets from ${c.master_short} — ${c.combined_pct}% supply [${c.risk}]`)
82
+ }
83
+ }
84
+
85
+ console.log(`\n${isSafe(report) ? "✅ SAFE — no cabal detected" : "🚫 SKIP — cabal detected"}`)
86
+ console.log(`\nVisual map: https://api.cabal-hunter.com/map?mint=${DEMO_MINT}`)
87
+ }
88
+
89
+ main().catch(console.error)
package/example_bot.py ADDED
@@ -0,0 +1,83 @@
1
+ """
2
+ Example: Integrate Cabal-Hunter into a Solana trading bot.
3
+ Checks for coordinated wallet clusters before executing any swap.
4
+ Cost: $0.05 USDC per check. Pays for itself the first time it blocks a rug.
5
+ """
6
+
7
+ import requests
8
+
9
+ CABAL_HUNTER_URL = "https://api.cabal-hunter.com/api/scan-cabal"
10
+ MAX_CABAL_SCORE = 35 # block if score >= 35 (controlled token)
11
+
12
+
13
+ def get_payment_instructions(mint: str) -> dict:
14
+ """Step 1: Get payment instructions from the API."""
15
+ resp = requests.post(CABAL_HUNTER_URL, json={"mintAddress": mint})
16
+ if resp.status_code == 402:
17
+ return resp.json()["payment"]
18
+ raise ValueError(f"Unexpected response: {resp.status_code}")
19
+
20
+
21
+ def check_cabal(mint: str, payment_tx_sig: str) -> dict:
22
+ """Step 2: Submit analysis with payment proof."""
23
+ resp = requests.post(
24
+ CABAL_HUNTER_URL,
25
+ json={"mintAddress": mint},
26
+ headers={"X-Payment-Signature": payment_tx_sig},
27
+ )
28
+ if resp.status_code == 200:
29
+ return resp.json()
30
+ raise ValueError(f"Analysis failed: {resp.status_code} {resp.text}")
31
+
32
+
33
+ def is_safe_to_buy(mint: str, payment_tx_sig: str) -> tuple[bool, str]:
34
+ """
35
+ Returns (safe, reason).
36
+ safe=True means proceed with the trade.
37
+ safe=False means the token has detected cabal risk — skip.
38
+ """
39
+ try:
40
+ result = check_cabal(mint, payment_tx_sig)
41
+ score = result.get("cabal_score", 0)
42
+ risk = result.get("risk", "CLEAN")
43
+
44
+ if result.get("is_controlled") or score >= MAX_CABAL_SCORE:
45
+ clusters = result.get("coordinated_clusters", [])
46
+ c = clusters[0] if clusters else {}
47
+ reason = (
48
+ f"CABAL DETECTED — Score {score}/100 — "
49
+ f"{c.get('wallet_count','?')} coordinated wallets holding "
50
+ f"{c.get('combined_pct','?')}% of supply"
51
+ )
52
+ return False, reason
53
+
54
+ return True, f"CLEAN — Score {score}/100 — {result.get('wallets_checked','?')} wallets traced"
55
+
56
+ except Exception as e:
57
+ # Fail safe: skip trade on any error
58
+ return False, f"Cabal check failed ({e}) — skipping trade as precaution"
59
+
60
+
61
+ # ── Example usage ─────────────────────────────────────────────────────────────
62
+
63
+ if __name__ == "__main__":
64
+ token_mint = "PASTE_TOKEN_MINT_HERE"
65
+
66
+ # Step 1: Get payment instructions
67
+ print(f"Checking {token_mint[:8]}…")
68
+ payment = get_payment_instructions(token_mint)
69
+ print(f" → Send {payment['amount_usdc']} USDC to {payment['recipient']}")
70
+ print(f" → Memo: {payment['memo_required']}")
71
+
72
+ # Step 2: You send the USDC (via your wallet SDK), get the tx sig
73
+ payment_sig = input("Paste your transaction signature: ").strip()
74
+
75
+ # Step 3: Check result
76
+ safe, reason = is_safe_to_buy(token_mint, payment_sig)
77
+ print(f"\n{'✅ SAFE' if safe else '🚫 BLOCKED'}: {reason}")
78
+
79
+ if safe:
80
+ print("Proceeding with swap…")
81
+ # execute_swap(token_mint, sol_amount)
82
+ else:
83
+ print("Trade cancelled — protecting your capital.")
package/glama.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "$schema": "https://glama.ai/mcp/schemas/server.json",
3
+ "maintainers": ["paulf280-ui"]
4
+ }
package/package.json CHANGED
@@ -1,58 +1,28 @@
1
1
  {
2
2
  "name": "cabal-hunter-mcp",
3
- "version": "0.1.0",
4
- "description": "MCP server for on-chain Solana cabal & rug detection — exit-liquidity risk verdict, funding-cluster + same-block-bundle + coordinated-dump detection, serial-rug deployer history, and honeypot check for any token mint. Run with npx, no API key. 250 free scans/month.",
3
+ "version": "1.0.1",
4
+ "description": "Local stdio MCP server for Cabal-Hunter — on-chain Solana token cabal & rug detection. Proxies to api.cabal-hunter.com.",
5
5
  "type": "module",
6
6
  "bin": {
7
- "cabal-hunter-mcp": "index.js"
7
+ "cabal-hunter-mcp": "server/index.mjs"
8
+ },
9
+ "main": "server/index.mjs",
10
+ "scripts": {
11
+ "start": "node server/index.mjs"
8
12
  },
9
- "main": "index.js",
10
- "files": [
11
- "index.js",
12
- "README.md",
13
- "LICENSE"
14
- ],
15
13
  "engines": {
16
14
  "node": ">=18"
17
15
  },
18
- "scripts": {
19
- "start": "node index.js"
20
- },
21
16
  "dependencies": {
22
- "@modelcontextprotocol/sdk": "^1.0.0"
17
+ "@modelcontextprotocol/sdk": "^1.7.0"
23
18
  },
24
19
  "keywords": [
25
20
  "mcp",
26
- "model-context-protocol",
27
- "mcp-server",
28
21
  "solana",
29
- "rug-check",
30
22
  "rug-detection",
31
- "rugcheck",
32
- "cabal-detection",
33
- "memecoin",
34
- "pump-fun",
35
- "pumpfun",
36
- "token-safety",
37
- "honeypot-detection",
38
- "exit-liquidity",
39
- "trading-bot",
40
- "ai-agent",
41
- "ai-agents",
42
- "web3",
43
- "defi",
44
- "claude",
45
- "cursor",
46
- "elizaos"
23
+ "cabal",
24
+ "trading",
25
+ "model-context-protocol"
47
26
  ],
48
- "license": "MIT",
49
- "author": "Cabal-Hunter (https://api.cabal-hunter.com)",
50
- "homepage": "https://api.cabal-hunter.com",
51
- "repository": {
52
- "type": "git",
53
- "url": "git+https://github.com/paulf280-ui/cabal-hunter-mcp.git"
54
- },
55
- "bugs": {
56
- "url": "https://github.com/paulf280-ui/cabal-hunter-mcp/issues"
57
- }
27
+ "license": "MIT"
58
28
  }
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Cabal-Hunter — local stdio MCP server.
4
+ *
5
+ * A thin Model Context Protocol server that exposes one tool, `check_cabal_risk`,
6
+ * and proxies to the hosted Cabal-Hunter API (https://api.cabal-hunter.com).
7
+ * Drop it into any MCP client (Claude Desktop, Cursor, ElizaOS) to give an agent
8
+ * a pre-trade safety check that catches coordinated wallet cabals, same-block
9
+ * Jito bundles, the dev's launch track record (peak market cap per past token +
10
+ * pump-and-dump history) and live coordinated dumps on any Solana mint before it
11
+ * signs a swap.
12
+ *
13
+ * Free tier: 100 scans/month. Beyond that, scans are $0.02 USDC via x402 on
14
+ * Solana — when a scan needs payment the API returns HTTP 402 with the payment
15
+ * instructions, which this tool surfaces to the caller.
16
+ *
17
+ * Uses the low-level Server API + JSON-Schema tool definitions for maximum
18
+ * compatibility across @modelcontextprotocol/sdk versions.
19
+ */
20
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
21
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
22
+ import {
23
+ ListToolsRequestSchema,
24
+ CallToolRequestSchema,
25
+ } from "@modelcontextprotocol/sdk/types.js";
26
+
27
+ const API_BASE = process.env.CABAL_HUNTER_API || "https://api.cabal-hunter.com";
28
+ const SCAN_URL = `${API_BASE}/api/scan-cabal`;
29
+
30
+ const server = new Server(
31
+ { name: "cabal-hunter", version: "1.0.0" },
32
+ { capabilities: { tools: {} } }
33
+ );
34
+
35
+ const CHECK_CABAL_RISK = {
36
+ name: "check_cabal_risk",
37
+ description:
38
+ "Scan a Solana token mint for coordinated wallet cabals, same-block Jito " +
39
+ "bundle buys, the dev's launch track record (peak market cap per past token " +
40
+ "+ pump-and-dump history) and live coordinated dumps. Returns an " +
41
+ "Exit-Liquidity Risk verdict (cabal_score 0-100, risk level, is_controlled, " +
42
+ "coordinated wallet clusters) so a trading agent can decide whether it is " +
43
+ "about to become exit liquidity BEFORE it signs a swap. Works on pump.fun, " +
44
+ "PumpSwap and Raydium tokens.",
45
+ inputSchema: {
46
+ type: "object",
47
+ properties: {
48
+ mintAddress: {
49
+ type: "string",
50
+ description: "The Solana token mint address (base58) to scan.",
51
+ },
52
+ },
53
+ required: ["mintAddress"],
54
+ },
55
+ };
56
+
57
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
58
+ tools: [CHECK_CABAL_RISK],
59
+ }));
60
+
61
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
62
+ if (request.params.name !== "check_cabal_risk") {
63
+ throw new Error(`Unknown tool: ${request.params.name}`);
64
+ }
65
+ const mintAddress = request.params.arguments?.mintAddress;
66
+ if (!mintAddress || typeof mintAddress !== "string") {
67
+ return {
68
+ isError: true,
69
+ content: [{ type: "text", text: "mintAddress is required (base58 mint string)." }],
70
+ };
71
+ }
72
+
73
+ try {
74
+ const resp = await fetch(SCAN_URL, {
75
+ method: "POST",
76
+ headers: { "Content-Type": "application/json" },
77
+ body: JSON.stringify({ mintAddress }),
78
+ });
79
+
80
+ // x402: payment required — surface the instructions rather than failing.
81
+ if (resp.status === 402) {
82
+ const body = await resp.json().catch(() => ({}));
83
+ return {
84
+ content: [
85
+ {
86
+ type: "text",
87
+ text:
88
+ "Payment required (x402). Free tier exhausted — this scan costs " +
89
+ "$0.02 USDC on Solana.\n\n" +
90
+ JSON.stringify(body.payment || body, null, 2),
91
+ },
92
+ ],
93
+ };
94
+ }
95
+
96
+ if (!resp.ok) {
97
+ const text = await resp.text().catch(() => "");
98
+ return {
99
+ isError: true,
100
+ content: [{ type: "text", text: `Scan failed: HTTP ${resp.status} ${text}` }],
101
+ };
102
+ }
103
+
104
+ const data = await resp.json();
105
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
106
+ } catch (err) {
107
+ return {
108
+ isError: true,
109
+ content: [{ type: "text", text: `Scan error: ${err?.message || String(err)}` }],
110
+ };
111
+ }
112
+ });
113
+
114
+ async function main() {
115
+ const transport = new StdioServerTransport();
116
+ await server.connect(transport);
117
+ // stdio transport keeps the process alive; log to stderr so stdout stays clean.
118
+ console.error("cabal-hunter MCP server running on stdio");
119
+ }
120
+
121
+ main().catch((err) => {
122
+ console.error("fatal:", err);
123
+ process.exit(1);
124
+ });
package/index.js DELETED
@@ -1,95 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * cabal-hunter-mcp — local MCP server for on-chain Solana cabal/rug detection.
4
- *
5
- * Exposes one tool, `check_cabal_risk`, that scans any Solana token mint and
6
- * returns an exit-liquidity risk verdict (SAFE / REVIEW / AVOID), a 0-100 cabal
7
- * score, funding-cluster + same-block-bundle + coordinated-dump detection,
8
- * serial-rug deployer history, and a honeypot (freeze / Token-2022) check.
9
- *
10
- * It is a thin stdio wrapper over the hosted Cabal-Hunter API
11
- * (https://api.cabal-hunter.com) so any MCP client — Claude Desktop, Claude
12
- * Code, Cursor, VS Code, ElizaOS — can run it with `npx cabal-hunter-mcp`.
13
- *
14
- * Free tier: 250 scans/month per IP, no signup, no key. To use a prepaid key
15
- * (e.g. $9/mo unlimited), set CABAL_HUNTER_API_KEY.
16
- */
17
- import { Server } from "@modelcontextprotocol/sdk/server/index.js";
18
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
19
- import {
20
- ListToolsRequestSchema,
21
- CallToolRequestSchema,
22
- } from "@modelcontextprotocol/sdk/types.js";
23
-
24
- const API = (process.env.CABAL_HUNTER_API || "https://api.cabal-hunter.com").replace(/\/+$/, "");
25
- const API_KEY = process.env.CABAL_HUNTER_API_KEY || "";
26
-
27
- const TOOL = {
28
- name: "check_cabal_risk",
29
- description:
30
- "Real-time on-chain coordinated-wallet (cabal) and rug detection for any " +
31
- "Solana token mint. One call returns an Exit-Liquidity Risk verdict " +
32
- "(SAFE | REVIEW | AVOID), a 0-100 cabal score, funding-cluster detection " +
33
- "(top holders funded by the same source), same-block Jito-bundle detection, " +
34
- "coordinated-dump detection, serial-rug deployer history (e.g. 'launched 14, " +
35
- "13 dead'), a honeypot check (freeze authority + Token-2022 traps), and " +
36
- "on-chain evidence transactions for every flag. Use it before an agent buys a " +
37
- "pump.fun / PumpSwap / Raydium token to answer: are you the exit liquidity? " +
38
- "Free: 250 scans/month, no API key required.",
39
- inputSchema: {
40
- type: "object",
41
- properties: {
42
- mint: {
43
- type: "string",
44
- description:
45
- "The Solana token mint (contract) address to scan, e.g. " +
46
- "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
47
- },
48
- },
49
- required: ["mint"],
50
- },
51
- };
52
-
53
- const server = new Server(
54
- { name: "cabal-hunter", version: "0.1.0" },
55
- { capabilities: { tools: {} } }
56
- );
57
-
58
- server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [TOOL] }));
59
-
60
- server.setRequestHandler(CallToolRequestSchema, async (req) => {
61
- const { name, arguments: args } = req.params;
62
- if (name !== TOOL.name) {
63
- return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
64
- }
65
- const mint = String(args?.mint || "").trim();
66
- if (!mint) {
67
- return {
68
- content: [{ type: "text", text: "Error: 'mint' (a Solana token mint address) is required." }],
69
- isError: true,
70
- };
71
- }
72
- const url = `${API}/api/scan-cabal?mintAddress=${encodeURIComponent(mint)}`;
73
- const headers = { Accept: "application/json" };
74
- if (API_KEY) headers["X-API-Key"] = API_KEY;
75
- try {
76
- const res = await fetch(url, { headers });
77
- const text = await res.text();
78
- if (!res.ok) {
79
- return {
80
- content: [{ type: "text", text: `Cabal-Hunter API error ${res.status}: ${text.slice(0, 800)}` }],
81
- isError: true,
82
- };
83
- }
84
- return { content: [{ type: "text", text }] };
85
- } catch (e) {
86
- return {
87
- content: [{ type: "text", text: `Request to Cabal-Hunter failed: ${e?.message || String(e)}` }],
88
- isError: true,
89
- };
90
- }
91
- });
92
-
93
- const transport = new StdioServerTransport();
94
- await server.connect(transport);
95
- console.error(`cabal-hunter MCP server running on stdio → ${API}`);