@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.
Files changed (4) hide show
  1. package/README.md +90 -0
  2. package/SKILL.md +202 -0
  3. package/index.mjs +230 -0
  4. 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
+ }