@clusteragent/cluster-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -0
- package/SKILL.md +202 -0
- package/index.mjs +230 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# cluster
|
|
2
|
+
|
|
3
|
+
**The runtime layer for agentic finance on Robinhood Chain.** Self-hostable index of
|
|
4
|
+
AI financial agents — tokenized stocks + crypto, real Uniswap v3 swaps, persistent
|
|
5
|
+
memory, and a 24-model LLM gateway in one MCP server.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @clusteragent/cluster-mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## What it does
|
|
12
|
+
|
|
13
|
+
| Capability | Tools |
|
|
14
|
+
|---|---|
|
|
15
|
+
| Live market data — 192 tokenized stocks/ETFs + native crypto (PONS, WETH, USDG, CLIPPY, KARMA, …) | `get_quotes` `get_movers` `get_news` `get_chart` |
|
|
16
|
+
| Real swaps on Robinhood Chain (4663) — quoted here, **signed by your wallet** (non-custodial) | `quote_swap` `trade_status` `wallet_balances` |
|
|
17
|
+
| Payout basket & distributions — the public record of every $CLST cycle | `get_payout_basket` `get_distributions` |
|
|
18
|
+
| Persistent memory per wallet — deduped, recency-scored, survives sessions | `memory_retain` `memory_recall` |
|
|
19
|
+
| LLM gateway — 24 models incl. GPT-6 Astra, Claude, GLM; `thinking` mode for deep reasoning | `chat` `get_models` `get_credits` |
|
|
20
|
+
| API keys with per-request metering (requests / tokens / USD) | `create_key` `key_usage` |
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
### MCP (Claude, Codex, Hermes, OpenClaw, any MCP runtime)
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"cluster": {
|
|
30
|
+
"command": "npx",
|
|
31
|
+
"args": ["-y", "@clusteragent/cluster-mcp"],
|
|
32
|
+
"env": {
|
|
33
|
+
"CLUSTER_API_URL": "https://your-cluster-host",
|
|
34
|
+
"CLUSTER_API_KEY": "clst_...",
|
|
35
|
+
"CLUSTER_WALLET": "0x..."
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Skill
|
|
43
|
+
|
|
44
|
+
Copy [SKILL.md](./SKILL.md) into your agent's skills directory — it teaches the
|
|
45
|
+
agent the full flow: key creation, market data, swap building, receipt proof.
|
|
46
|
+
|
|
47
|
+
### Self-host the backend
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
git clone https://github.com/clusteragent/cluster
|
|
51
|
+
cd cluster/server
|
|
52
|
+
cp .env.example .env # set LLM gateway key etc.
|
|
53
|
+
pip install -r requirements.txt
|
|
54
|
+
uvicorn app.main:app --port 8000
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Then point `CLUSTER_API_URL` at it. Market data works out of the box; the LLM
|
|
58
|
+
gateway needs your own provider key.
|
|
59
|
+
|
|
60
|
+
## The mechanism
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
fees in ──▶ vault ──▶ keeper bot buys the 19-name basket ──▶ $CLST holders paid pro-rata
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Every agent action accrues fees. The keeper bot sweeps the payout basket at live
|
|
67
|
+
market prices. Holding is the position — no staking, no claiming. Every cycle is
|
|
68
|
+
public: `GET /api/distributions`.
|
|
69
|
+
|
|
70
|
+
## The agents
|
|
71
|
+
|
|
72
|
+
Sixteen capabilities, each with its own skill pack:
|
|
73
|
+
|
|
74
|
+
**Trading** Relay · Pivot — **Research** Scout · Sifter · Quill — **Analysis** Argus · Prism · Census — **Finance** Ledger · Remit · Margin — **Memory** Memoria · Echo — **Crypto** Nexus · Vault · Oracle
|
|
75
|
+
|
|
76
|
+
## Honesty by construction
|
|
77
|
+
|
|
78
|
+
- No fabricated numbers: pre-launch payout data returns honest zeros, never invented rows
|
|
79
|
+
- Swaps never touch a private key on our side — the API quotes, your wallet signs
|
|
80
|
+
- API keys are stored as SHA-256 hashes and shown exactly once
|
|
81
|
+
- A quote is a prediction; the receipt is the proof — parse Transfer logs to see what actually arrived
|
|
82
|
+
|
|
83
|
+
## Chain info
|
|
84
|
+
|
|
85
|
+
Robinhood Chain · chain id **4663** · Uniswap v3 ·
|
|
86
|
+
Router `0xcaf681a6…5cb2` · QuoterV2 `0x33e885ed…a9e7`
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cluster
|
|
3
|
+
description: Cluster — self-hostable index of AI financial agents. Trade tokenized stocks and crypto on Robinhood Chain (4663) with real Uniswap v3 swaps, get live quotes for 193 tokenized instruments, read the payout basket, check distribution cycles, use persistent memory per wallet, and chat with 24 LLM models. Use when the user wants tokenized stock or crypto prices, swap execution on Robinhood Chain, portfolio and basket data, agent run logs, persistent memory storage, or an LLM gateway — including agents like Relay (trading), Scout (research), Argus (on-chain analysis), Vault (treasury), and Oracle (price feeds). Supports the full 192-instrument tokenized stock universe plus native crypto (PONS, WETH, USDG, CLIPPY, KARMA and more).
|
|
4
|
+
metadata:
|
|
5
|
+
{
|
|
6
|
+
"clawdbot":
|
|
7
|
+
{
|
|
8
|
+
"emoji": "🧩",
|
|
9
|
+
"homepage": "https://github.com/clusteragent/cluster",
|
|
10
|
+
"requires": { "bins": [], "env": [] },
|
|
11
|
+
},
|
|
12
|
+
}
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Cluster
|
|
16
|
+
|
|
17
|
+
The runtime layer for agentic finance on Robinhood Chain. Persistent memory, live
|
|
18
|
+
market data over a 193-instrument tokenized stock universe, real Uniswap v3 swaps,
|
|
19
|
+
and a 24-model LLM gateway — one skill, every MCP runtime.
|
|
20
|
+
|
|
21
|
+
Two ways to run it:
|
|
22
|
+
|
|
23
|
+
1. **Hosted API (default)** — no install beyond this skill; point tools at the public
|
|
24
|
+
cluster endpoint and authenticate with a cluster API key
|
|
25
|
+
2. **Self-hosted** — run the cluster backend yourself (Docker or bare Node/Python);
|
|
26
|
+
all tools work identically against your own deployment
|
|
27
|
+
|
|
28
|
+
## Getting an API Key
|
|
29
|
+
|
|
30
|
+
Every wallet gets **$5 of inference credit** on first connect. Two ways:
|
|
31
|
+
|
|
32
|
+
**Option A: In-app (recommended)**
|
|
33
|
+
|
|
34
|
+
1. Open the cluster app and connect your wallet
|
|
35
|
+
2. Sign once — a session starts; no more prompts for 60 minutes
|
|
36
|
+
3. Go to **API & Settings → Generate new key**
|
|
37
|
+
4. Copy the key (`clst_<prefix>_<secret>`) — it is shown **exactly once**
|
|
38
|
+
|
|
39
|
+
**Option B: Headless (agents)**
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# 1. Get a signing challenge for your wallet
|
|
43
|
+
curl "https://YOUR-CLUSTER-HOST/api/auth/challenge?wallet=0xYOUR_ADDRESS"
|
|
44
|
+
|
|
45
|
+
# 2. Sign the message with personal_sign (any EVM signer), then exchange it
|
|
46
|
+
curl -X POST "https://YOUR-CLUSTER-HOST/api/auth/session" \
|
|
47
|
+
-H "Content-Type: application/json" \
|
|
48
|
+
-d '{"wallet":"0xYOUR_ADDRESS","signature":"0xSIGNED_MESSAGE"}'
|
|
49
|
+
# → { "session_token": "...", "expires_in": 3600 }
|
|
50
|
+
|
|
51
|
+
# 3. Create a key with the session token
|
|
52
|
+
curl -X POST "https://YOUR-CLUSTER-HOST/api/keys" \
|
|
53
|
+
-H "Content-Type: application/json" \
|
|
54
|
+
-d '{"wallet":"0xYOUR_ADDRESS","session_token":"...","name":"my-agent"}'
|
|
55
|
+
# → { "key": "clst_...", ... } — store it, it cannot be recovered
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Option 1: MCP Server (Recommended)
|
|
59
|
+
|
|
60
|
+
### Install
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
bunx @clusteragent/cluster-mcp # run directly
|
|
64
|
+
# or
|
|
65
|
+
npm install -g @clusteragent/cluster-mcp
|
|
66
|
+
cluster-mcp # starts the MCP server on stdio
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Wire it into your runtime
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"mcpServers": {
|
|
74
|
+
"cluster": {
|
|
75
|
+
"command": "npx",
|
|
76
|
+
"args": ["-y", "@clusteragent/cluster-mcp"],
|
|
77
|
+
"env": {
|
|
78
|
+
"CLUSTER_API_URL": "https://YOUR-CLUSTER-HOST",
|
|
79
|
+
"CLUSTER_API_KEY": "clst_your_key_here"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`CLUSTER_API_URL` defaults to the hosted endpoint; set it to your own deployment for
|
|
87
|
+
self-hosting. `CLUSTER_API_KEY` is required for wallet-scoped tools (chat, memory,
|
|
88
|
+
keys); market data tools work without one.
|
|
89
|
+
|
|
90
|
+
## Option 2: REST API (Direct)
|
|
91
|
+
|
|
92
|
+
No MCP needed — call the API with curl, fetch, or any HTTP client.
|
|
93
|
+
|
|
94
|
+
### Authentication
|
|
95
|
+
|
|
96
|
+
Wallet-scoped requests accept either:
|
|
97
|
+
|
|
98
|
+
- `session_token` — from the sign-once session flow above (60 minutes)
|
|
99
|
+
- `X-API-Key: clst_...` — for external callers; usage is metered per request
|
|
100
|
+
|
|
101
|
+
Market data needs no auth.
|
|
102
|
+
|
|
103
|
+
### Endpoints Summary
|
|
104
|
+
|
|
105
|
+
| Endpoint | Method | Auth | Description |
|
|
106
|
+
|----------|--------|------|-------------|
|
|
107
|
+
| `/api/market/quotes?symbols=NVDA,TSLA` | GET | none | Batch quotes + ~1 month of daily closes |
|
|
108
|
+
| `/api/market/movers` | GET | none | Gainers, losers, sector heat (192 covered) |
|
|
109
|
+
| `/api/market/news` | GET | none | Yahoo Finance headlines |
|
|
110
|
+
| `/api/market/chart/{symbol}` | GET | none | Candles + series per timeframe |
|
|
111
|
+
| `/api/index` | GET | none | Index composition, on-chain verified count |
|
|
112
|
+
| `/api/index/payout-basket` | GET | none | The 19-name payout basket with weights |
|
|
113
|
+
| `/api/distributions` | GET | none | Distribution cycles, payroll, treasury |
|
|
114
|
+
| `/api/trade/quote` | GET | none | Uniswap v3 quote (token, side, amount in wei, via) |
|
|
115
|
+
| `/api/trade/status` | GET | none | Router, quoter, gas, ETH price |
|
|
116
|
+
| `/api/trade/wallet/{address}` | GET | none | On-chain balances: native ETH + all holdings |
|
|
117
|
+
| `/api/chat` | POST | wallet/key | One completion — 24 models, `thinking` flag for extended reasoning |
|
|
118
|
+
| `/api/chat/models` | GET | none | Model list with context windows and pricing |
|
|
119
|
+
| `/api/chat/credits` | GET | none | Credit balance for a wallet |
|
|
120
|
+
| `/api/memory/retain` | POST | wallet/key | Store a durable memory note (deduped) |
|
|
121
|
+
| `/api/memory/recall` | POST | wallet/key | Semantic-ish recall of stored notes |
|
|
122
|
+
| `/api/keys` | GET/POST | wallet/key | List / create API keys |
|
|
123
|
+
| `/api/keys/usage` | GET | wallet/key | Metered usage: requests, tokens, USD |
|
|
124
|
+
|
|
125
|
+
### Quick Examples
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Live quotes
|
|
129
|
+
curl "https://YOUR-CLUSTER-HOST/api/market/quotes?symbols=NVDA,SPY,PONS"
|
|
130
|
+
|
|
131
|
+
# The payout basket — 19 instruments, weights sum to 100
|
|
132
|
+
curl "https://YOUR-CLUSTER-HOST/api/index/payout-basket"
|
|
133
|
+
|
|
134
|
+
# Quote a swap: 0.01 ETH → NVDA (amount in wei)
|
|
135
|
+
curl "https://YOUR-CLUSTER-HOST/api/trade/quote?token=0xd0601CE157Db5bdC3162BbaC2a2C8aF5320D9EEC&side=buy&amount=10000000000000000"
|
|
136
|
+
|
|
137
|
+
# Chat with extended reasoning
|
|
138
|
+
curl -X POST "https://YOUR-CLUSTER-HOST/api/chat" \
|
|
139
|
+
-H "Content-Type: application/json" \
|
|
140
|
+
-d '{"wallet":"0xYOUR_ADDRESS","model":"openai/gpt-6-astra","thinking":true,"messages":[{"role":"user","content":"Analyze NVDA momentum"}]}'
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Executing Swaps (client-side, non-custodial)
|
|
144
|
+
|
|
145
|
+
Cluster never touches a private key. The API quotes and builds calldata; **your
|
|
146
|
+
wallet signs and broadcasts**:
|
|
147
|
+
|
|
148
|
+
1. `GET /api/trade/quote` — get the best route + `amountOut`
|
|
149
|
+
2. Build the tx: buy = `multicall([exactInput, refundETH])` with `msg.value`;
|
|
150
|
+
sell = approve the router, then `multicall([exactInput, unwrapWETH9])`
|
|
151
|
+
3. Sign with your own signer (wagmi, ethers, viem) and broadcast
|
|
152
|
+
4. Poll `eth_getTransactionReceipt` — parse Transfer logs to confirm what actually
|
|
153
|
+
arrived (a quote is a prediction; a receipt is proof)
|
|
154
|
+
|
|
155
|
+
Key addresses on Robinhood Chain (4663):
|
|
156
|
+
|
|
157
|
+
| Contract | Address |
|
|
158
|
+
|----------|---------|
|
|
159
|
+
| SwapRouter02 | `0xcaf681a66d020601342297493863e78c959e5cb2` |
|
|
160
|
+
| QuoterV2 | `0x33e885ed0ec9bf04ecfb19341582aadcb4c8a9e7` |
|
|
161
|
+
| WETH | `0x0Bd7D308f8E1639FAb988df18A8011f41EAcAD73` |
|
|
162
|
+
| USDG | `0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168` |
|
|
163
|
+
|
|
164
|
+
## The Agents
|
|
165
|
+
|
|
166
|
+
Sixteen agent capabilities, each with its own skill pack. Running one logs the
|
|
167
|
+
interaction to your wallet's history; after the $CLST token launch, fees from agent
|
|
168
|
+
work stream to holders through the payout basket.
|
|
169
|
+
|
|
170
|
+
| Agent | Ticker | Category | Trigger |
|
|
171
|
+
|-------|--------|----------|---------|
|
|
172
|
+
| Relay | RLY | Trading | Per swap |
|
|
173
|
+
| Scout | SCT | Research | Per report |
|
|
174
|
+
| Ledger | FIN | Finance | Per task |
|
|
175
|
+
| Argus | ARG | Analysis | Per query |
|
|
176
|
+
| Pivot | PVT | Trading | Per swap |
|
|
177
|
+
| Prism | PRSM | Analysis | Per query |
|
|
178
|
+
| Memoria | MEM | Memory | Per task |
|
|
179
|
+
| Sifter | SFT | Research | Per report |
|
|
180
|
+
| Remit | RMT | Finance | Per task |
|
|
181
|
+
| Nexus | NXS | Crypto | Per task |
|
|
182
|
+
| Echo | ECH | Memory | Per query |
|
|
183
|
+
| Census | CNS | Analysis | Per query |
|
|
184
|
+
| Vault | VLT | Crypto | Per task |
|
|
185
|
+
| Quill | QLL | Research | Per report |
|
|
186
|
+
| Oracle | ORC | Crypto | Per query |
|
|
187
|
+
| Margin | MRG | Finance | Per task |
|
|
188
|
+
|
|
189
|
+
## The Payout Mechanism
|
|
190
|
+
|
|
191
|
+
Fees in → basket out. Every agent action accrues fees in the vault; the keeper bot
|
|
192
|
+
sweeps the **19-name payout basket** at live market prices; $CLST holders are paid
|
|
193
|
+
pro-rata every cycle. No staking, no claiming — holding is the position. All
|
|
194
|
+
distribution data is public: `GET /api/distributions` returns every cycle, per
|
|
195
|
+
address, from the first one onward.
|
|
196
|
+
|
|
197
|
+
## Rate Limits & Credits
|
|
198
|
+
|
|
199
|
+
- Chat: 30 requests/minute per wallet
|
|
200
|
+
- Every wallet starts with **$5 of inference credit** — metered per token, per model
|
|
201
|
+
- API key calls are metered the same way and visible in realtime under `/api/keys/usage`
|
|
202
|
+
- Top-ups are not open yet; credit is the only gate
|
package/index.mjs
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Cluster MCP server — the runtime layer for agentic finance on Robinhood Chain.
|
|
4
|
+
*
|
|
5
|
+
* Tools (all zero private keys — swaps are quoted here, signed by YOUR wallet):
|
|
6
|
+
* get_quotes — batch quotes + daily closes for tokenized stocks & crypto
|
|
7
|
+
* get_movers — gainers, losers, sector heat across 192 instruments
|
|
8
|
+
* get_news — Yahoo Finance headlines
|
|
9
|
+
* get_chart — candles + series per symbol/timeframe
|
|
10
|
+
* get_index — index composition, on-chain verified
|
|
11
|
+
* get_payout_basket — the 19-name basket that pays $CLST holders
|
|
12
|
+
* get_distributions — payout cycles, payroll, treasury (public record)
|
|
13
|
+
* quote_swap — Uniswap v3 route + amountOut (amount in wei)
|
|
14
|
+
* trade_status — router, quoter, gas, ETH price
|
|
15
|
+
* wallet_balances — on-chain balances for any address (native ETH + holdings)
|
|
16
|
+
* get_models — 24-model LLM gateway list w/ pricing
|
|
17
|
+
* chat — one completion (thinking flag = extended reasoning)
|
|
18
|
+
* get_credits — inference credit balance for a wallet
|
|
19
|
+
* memory_retain — store a durable, deduped memory note
|
|
20
|
+
* memory_recall — recall stored notes
|
|
21
|
+
* list_keys / create_key / key_usage — API key management
|
|
22
|
+
*
|
|
23
|
+
* Env:
|
|
24
|
+
* CLUSTER_API_URL — cluster backend base URL (default: hosted endpoint)
|
|
25
|
+
* CLUSTER_API_KEY — clst_... key for wallet-scoped tools (optional for market data)
|
|
26
|
+
* CLUSTER_WALLET — default wallet address for wallet-scoped tools
|
|
27
|
+
*/
|
|
28
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
29
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
30
|
+
import {
|
|
31
|
+
ListToolsRequestSchema,
|
|
32
|
+
CallToolRequestSchema,
|
|
33
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
34
|
+
|
|
35
|
+
const API = (process.env.CLUSTER_API_URL || "https://applicant-tremendous-respective-mono.trycloudflare.com").replace(/\/$/, "");
|
|
36
|
+
const KEY = process.env.CLUSTER_API_KEY || "";
|
|
37
|
+
const WALLET = process.env.CLUSTER_WALLET || "";
|
|
38
|
+
|
|
39
|
+
async function api(path, { method = "GET", body } = {}) {
|
|
40
|
+
const headers = { "Content-Type": "application/json", Accept: "application/json" };
|
|
41
|
+
if (KEY) headers["X-API-Key"] = KEY;
|
|
42
|
+
const res = await fetch(`${API}${path}`, {
|
|
43
|
+
method,
|
|
44
|
+
headers,
|
|
45
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
46
|
+
});
|
|
47
|
+
const text = await res.text();
|
|
48
|
+
let data;
|
|
49
|
+
try {
|
|
50
|
+
data = JSON.parse(text);
|
|
51
|
+
} catch {
|
|
52
|
+
data = { raw: text.slice(0, 400) };
|
|
53
|
+
}
|
|
54
|
+
if (!res.ok) {
|
|
55
|
+
return { error: true, status: res.status, detail: data?.detail ?? data?.raw ?? text.slice(0, 200) };
|
|
56
|
+
}
|
|
57
|
+
return data;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const json = (d) => ({ content: [{ type: "text", text: JSON.stringify(d, null, 2) }] });
|
|
61
|
+
const err = (msg) => ({ content: [{ type: "text", text: `Error: ${msg}` }], isError: true });
|
|
62
|
+
|
|
63
|
+
function walletArgs(args) {
|
|
64
|
+
const wallet = args?.wallet || WALLET;
|
|
65
|
+
if (!wallet) throw new Error("No wallet address — pass `wallet` or set CLUSTER_WALLET");
|
|
66
|
+
return { wallet, session_token: args?.session_token || undefined, signature: args?.signature || undefined };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const TOOLS = [
|
|
70
|
+
{
|
|
71
|
+
name: "get_quotes",
|
|
72
|
+
description: "Batch quotes + ~1 month of daily closes for tokenized stocks/ETFs and crypto on Robinhood Chain. Symbols: NVDA, SPY, TSLA, PONS, WETH, USDG, CLIPPY, KARMA, ...",
|
|
73
|
+
inputSchema: { type: "object", properties: { symbols: { type: "string", description: "Comma-separated symbols, e.g. 'NVDA,SPY,PONS'" } }, required: ["symbols"] },
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: "get_movers",
|
|
77
|
+
description: "Live gainers, losers and sector heat across the 192-instrument universe.",
|
|
78
|
+
inputSchema: { type: "object", properties: { limit: { type: "number", description: "Rows per side (default 10)" } } },
|
|
79
|
+
},
|
|
80
|
+
{ name: "get_news", description: "Yahoo Finance market headlines.", inputSchema: { type: "object", properties: { limit: { type: "number" } } } },
|
|
81
|
+
{
|
|
82
|
+
name: "get_chart",
|
|
83
|
+
description: "Price series + candles for a symbol (NVDA, SPY, PONS, ...).",
|
|
84
|
+
inputSchema: { type: "object", properties: { symbol: { type: "string" }, tf: { type: "string", description: "1d|5d|1mo|3mo|6mo|1y" } }, required: ["symbol"] },
|
|
85
|
+
},
|
|
86
|
+
{ name: "get_index", description: "Cluster index composition: 193 instruments, on-chain verified count, $CLST status.", inputSchema: { type: "object", properties: {} } },
|
|
87
|
+
{ name: "get_payout_basket", description: "The 19-name payout basket with weights — what $CLST holders get paid from.", inputSchema: { type: "object", properties: {} } },
|
|
88
|
+
{ name: "get_distributions", description: "Distribution cycles, payroll and treasury balance — the public payout record.", inputSchema: { type: "object", properties: {} } },
|
|
89
|
+
{
|
|
90
|
+
name: "quote_swap",
|
|
91
|
+
description: "Uniswap v3 route + amountOut for a swap on Robinhood Chain (4663). amount is in WEI of the input token. Read-only — execution happens in the user's wallet.",
|
|
92
|
+
inputSchema: {
|
|
93
|
+
type: "object",
|
|
94
|
+
properties: {
|
|
95
|
+
token: { type: "string", description: "Output token contract address" },
|
|
96
|
+
side: { type: "string", description: "buy (ETH->token) or sell (token->ETH)" },
|
|
97
|
+
amount: { type: "string", description: "Amount in wei of input token" },
|
|
98
|
+
via: { type: "string", description: "USDG or WETH hop preference" },
|
|
99
|
+
},
|
|
100
|
+
required: ["token", "side", "amount"],
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
{ name: "trade_status", description: "Router, quoter, WETH, USDG, gas price, ETH USD rate for Robinhood Chain.", inputSchema: { type: "object", properties: {} } },
|
|
104
|
+
{
|
|
105
|
+
name: "wallet_balances",
|
|
106
|
+
description: "On-chain balances for any address on Robinhood Chain: native ETH + every held token. Read-only, no auth.",
|
|
107
|
+
inputSchema: { type: "object", properties: { address: { type: "string" } }, required: ["address"] },
|
|
108
|
+
},
|
|
109
|
+
{ name: "get_models", description: "24-model LLM gateway list with context windows and USD pricing per 1M tokens.", inputSchema: { type: "object", properties: {} } },
|
|
110
|
+
{
|
|
111
|
+
name: "chat",
|
|
112
|
+
description: "One completion through the cluster LLM gateway (24 models). Set thinking=true for extended reasoning. Costs credit ($5 free per wallet).",
|
|
113
|
+
inputSchema: {
|
|
114
|
+
type: "object",
|
|
115
|
+
properties: {
|
|
116
|
+
wallet: { type: "string" },
|
|
117
|
+
model: { type: "string", description: "e.g. openai/gpt-6-astra, anthropic/..., glm/glm-5.3-flash (cheapest)" },
|
|
118
|
+
thinking: { type: "boolean", description: "Extended reasoning pass (uses more tokens)" },
|
|
119
|
+
messages: { type: "array", items: { type: "object", properties: { role: { type: "string" }, content: { type: "string" } } } },
|
|
120
|
+
},
|
|
121
|
+
required: ["messages"],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{ name: "get_credits", description: "Inference credit balance (granted/used/remaining) for a wallet.", inputSchema: { type: "object", properties: { wallet: { type: "string" } }, required: ["wallet"] } },
|
|
125
|
+
{
|
|
126
|
+
name: "memory_retain",
|
|
127
|
+
description: "Store a durable memory note for a wallet/bank. Deduped — identical content is skipped. Persists across sessions.",
|
|
128
|
+
inputSchema: { type: "object", properties: { bank_id: { type: "string", description: "Wallet address or bank id" }, content: { type: "string", description: "Max 4000 chars" }, title: { type: "string" }, tags: { type: "array", items: { type: "string" } } }, required: ["bank_id", "content"] },
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: "memory_recall",
|
|
132
|
+
description: "Recall memory notes for a wallet/bank, scored by recency-decay match.",
|
|
133
|
+
inputSchema: { type: "object", properties: { bank_id: { type: "string" }, query: { type: "string" }, limit: { type: "number" } }, required: ["bank_id", "query"] },
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
name: "create_key",
|
|
137
|
+
description: "Create a cluster API key (clst_...) for a wallet. Shown exactly once.",
|
|
138
|
+
inputSchema: { type: "object", properties: { wallet: { type: "string" }, name: { type: "string" }, session_token: { type: "string" }, signature: { type: "string" } }, required: ["wallet"] },
|
|
139
|
+
},
|
|
140
|
+
{ name: "key_usage", description: "Metered usage for a wallet's keys: requests, tokens, USD.", inputSchema: { type: "object", properties: { wallet: { type: "string" }, session_token: { type: "string" }, signature: { type: "string" } }, required: ["wallet"] } },
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
const server = new Server({ name: "cluster", version: "1.0.0" }, { capabilities: { tools: {} } });
|
|
144
|
+
|
|
145
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
146
|
+
|
|
147
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
148
|
+
const { name, arguments: args = {} } = req.params;
|
|
149
|
+
try {
|
|
150
|
+
switch (name) {
|
|
151
|
+
case "get_quotes":
|
|
152
|
+
return json(await api(`/api/market/quotes?symbols=${encodeURIComponent(args.symbols)}`));
|
|
153
|
+
case "get_movers":
|
|
154
|
+
return json(await api(`/api/market/movers?limit=${args.limit ?? 10}`));
|
|
155
|
+
case "get_news":
|
|
156
|
+
return json(await api(`/api/market/news?limit=${args.limit ?? 12}`));
|
|
157
|
+
case "get_chart":
|
|
158
|
+
return json(await api(`/api/market/chart/${encodeURIComponent(args.symbol)}?tf=${args.tf ?? "1mo"}`));
|
|
159
|
+
case "get_index":
|
|
160
|
+
return json(await api("/api/index"));
|
|
161
|
+
case "get_payout_basket":
|
|
162
|
+
return json(await api("/api/index/payout-basket"));
|
|
163
|
+
case "get_distributions":
|
|
164
|
+
return json(await api("/api/distributions"));
|
|
165
|
+
case "quote_swap": {
|
|
166
|
+
const qs = new URLSearchParams({ token: args.token, side: args.side ?? "buy", amount: args.amount });
|
|
167
|
+
if (args.via) qs.set("via", args.via);
|
|
168
|
+
return json(await api(`/api/trade/quote?${qs}`));
|
|
169
|
+
}
|
|
170
|
+
case "trade_status":
|
|
171
|
+
return json(await api("/api/trade/status"));
|
|
172
|
+
case "wallet_balances":
|
|
173
|
+
return json(await api(`/api/trade/wallet/${args.address}`));
|
|
174
|
+
case "get_models":
|
|
175
|
+
return json(await api("/api/chat/models"));
|
|
176
|
+
case "get_credits":
|
|
177
|
+
return json(await api(`/api/chat/credits?wallet=${encodeURIComponent(args.wallet)}`));
|
|
178
|
+
case "chat": {
|
|
179
|
+
const w = walletArgs(args);
|
|
180
|
+
return json(
|
|
181
|
+
await api("/api/chat", {
|
|
182
|
+
method: "POST",
|
|
183
|
+
body: {
|
|
184
|
+
wallet: w.wallet,
|
|
185
|
+
session_token: w.session_token,
|
|
186
|
+
signature: w.signature,
|
|
187
|
+
model: args.model ?? "glm/glm-5.3-flash",
|
|
188
|
+
thinking: args.thinking ?? false,
|
|
189
|
+
messages: args.messages,
|
|
190
|
+
},
|
|
191
|
+
}),
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
case "memory_retain": {
|
|
195
|
+
const w = walletArgs(args);
|
|
196
|
+
return json(
|
|
197
|
+
await api("/api/memory/retain", {
|
|
198
|
+
method: "POST",
|
|
199
|
+
body: { bank_id: w.wallet, wallet: w.wallet, session_token: w.session_token, signature: w.signature, content: args.content, title: args.title, tags: args.tags },
|
|
200
|
+
}),
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
case "memory_recall": {
|
|
204
|
+
const w = walletArgs(args);
|
|
205
|
+
return json(
|
|
206
|
+
await api("/api/memory/recall", {
|
|
207
|
+
method: "POST",
|
|
208
|
+
body: { bank_id: w.wallet, wallet: w.wallet, session_token: w.session_token, signature: w.signature, query: args.query, limit: args.limit ?? 10 },
|
|
209
|
+
}),
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
case "create_key": {
|
|
213
|
+
const w = walletArgs(args);
|
|
214
|
+
return json(await api("/api/keys", { method: "POST", body: { wallet: w.wallet, session_token: w.session_token, signature: w.signature, name: args.name ?? "default" } }));
|
|
215
|
+
}
|
|
216
|
+
case "key_usage": {
|
|
217
|
+
const w = walletArgs(args);
|
|
218
|
+
return json(await api(`/api/keys/usage?wallet=${encodeURIComponent(w.wallet)}&session_token=${encodeURIComponent(w.session_token ?? "")}&signature=${encodeURIComponent(w.signature ?? "")}`));
|
|
219
|
+
}
|
|
220
|
+
default:
|
|
221
|
+
return err(`Unknown tool: ${name}`);
|
|
222
|
+
}
|
|
223
|
+
} catch (e) {
|
|
224
|
+
return err(e.message ?? String(e));
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
const transport = new StdioServerTransport();
|
|
229
|
+
await server.connect(transport);
|
|
230
|
+
console.error(`cluster-mcp ready — API: ${API}`);
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@clusteragent/cluster-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Cluster MCP \u2014 self-hostable index of AI financial agents. Tokenized stocks + crypto on Robinhood Chain, persistent memory, 24-model LLM gateway.",
|
|
5
|
+
"main": "index.mjs",
|
|
6
|
+
"bin": {
|
|
7
|
+
"cluster-mcp": "index.mjs"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"files": [
|
|
11
|
+
"index.mjs",
|
|
12
|
+
"SKILL.md",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mcp",
|
|
17
|
+
"model-context-protocol",
|
|
18
|
+
"robinhood-chain",
|
|
19
|
+
"tokenized-stocks",
|
|
20
|
+
"crypto",
|
|
21
|
+
"uniswap-v3",
|
|
22
|
+
"ai-agents",
|
|
23
|
+
"persistent-memory",
|
|
24
|
+
"llm-gateway",
|
|
25
|
+
"defi"
|
|
26
|
+
],
|
|
27
|
+
"author": "clusteragent",
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/clusteragent/cluster.git"
|
|
32
|
+
},
|
|
33
|
+
"homepage": "https://github.com/clusteragent/cluster#readme",
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
39
|
+
}
|
|
40
|
+
}
|