@ironflowsh/mcp 0.7.0 → 0.8.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 +38 -18
- package/build/api.d.ts +3 -3
- package/build/api.d.ts.map +1 -1
- package/build/api.js +11 -11
- package/build/api.js.map +1 -1
- package/build/http.d.ts +3 -0
- package/build/http.d.ts.map +1 -0
- package/build/http.js +144 -0
- package/build/http.js.map +1 -0
- package/build/index.js +10 -68
- package/build/index.js.map +1 -1
- package/build/liquidations.d.ts +28 -0
- package/build/liquidations.d.ts.map +1 -0
- package/build/liquidations.js +77 -0
- package/build/liquidations.js.map +1 -0
- package/build/request.d.ts +8 -0
- package/build/request.d.ts.map +1 -0
- package/build/request.js +34 -0
- package/build/request.js.map +1 -0
- package/build/server.d.ts +5 -0
- package/build/server.d.ts.map +1 -0
- package/build/server.js +54 -0
- package/build/server.js.map +1 -0
- package/build/tools.d.ts.map +1 -1
- package/build/tools.js +128 -58
- package/build/tools.js.map +1 -1
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @ironflowsh/mcp
|
|
2
2
|
|
|
3
|
-
MCP server for [Ironflow](https://ironflow.sh): read-only Hyperliquid market data and wallet analytics for Claude
|
|
3
|
+
MCP server for [Ironflow](https://ironflow.sh): read-only Hyperliquid market data and wallet analytics for Claude, Cursor and any MCP client. It covers native perps, HIP-3 builder markets, HIP-4 outcome markets and spot. 33 tools, all read-only.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
No API key needed to start: keyless calls get 10 requests per minute and 24 hours of history. A free key from [ironflow.sh/key](https://ironflow.sh/key) raises that to 60 requests per minute and 30 days.
|
|
6
6
|
|
|
7
7
|
## Example questions
|
|
8
8
|
|
|
@@ -14,17 +14,40 @@ An API key is required. Request one at [ironflow.sh/api](https://ironflow.sh/api
|
|
|
14
14
|
|
|
15
15
|
> "Summarize this wallet's last 30 days: PnL, fees, maker share, funding paid."
|
|
16
16
|
|
|
17
|
-
##
|
|
17
|
+
## Hosted server (no install)
|
|
18
|
+
|
|
19
|
+
Connect by URL: `https://mcp.ironflow.sh/mcp` (Streamable HTTP).
|
|
18
20
|
|
|
19
21
|
```bash
|
|
20
|
-
|
|
22
|
+
# Claude Code
|
|
23
|
+
claude mcp add --transport http ironflow https://mcp.ironflow.sh/mcp
|
|
24
|
+
|
|
25
|
+
# with a free key
|
|
26
|
+
claude mcp add --transport http ironflow https://mcp.ironflow.sh/mcp \
|
|
27
|
+
--header "Authorization: Bearer if_your_api_key"
|
|
21
28
|
```
|
|
22
29
|
|
|
23
|
-
|
|
30
|
+
Claude desktop and claude.ai: Settings → Connectors → Add custom connector, paste the URL.
|
|
31
|
+
|
|
32
|
+
Cursor (`~/.cursor/mcp.json` or a project's `.cursor/mcp.json`):
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"ironflow": { "url": "https://mcp.ironflow.sh/mcp" }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
24
41
|
|
|
25
|
-
|
|
42
|
+
Clients that cannot send headers can pass the key as `?key=if_your_api_key` on the URL.
|
|
26
43
|
|
|
27
|
-
|
|
44
|
+
## Local server
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx -y @ironflowsh/mcp
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Requires Node.js 18+. Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, `%APPDATA%/Claude/claude_desktop_config.json` on Windows):
|
|
28
51
|
|
|
29
52
|
```json
|
|
30
53
|
{
|
|
@@ -38,21 +61,17 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
|
|
|
38
61
|
}
|
|
39
62
|
```
|
|
40
63
|
|
|
41
|
-
|
|
64
|
+
The `env` block is optional. Claude Code: `claude mcp add ironflow -- npx -y @ironflowsh/mcp`.
|
|
42
65
|
|
|
43
|
-
|
|
44
|
-
claude mcp add ironflow -e IRONFLOW_API_KEY=if_your_api_key -- npx -y @ironflowsh/mcp
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Cursor
|
|
48
|
-
|
|
49
|
-
Add the same `mcpServers` block to `~/.cursor/mcp.json` or a project's `.cursor/mcp.json`.
|
|
66
|
+
To host the HTTP server yourself: `npx -y -p @ironflowsh/mcp ironflow-mcp-http` (listens on `PORT`, default 8080, path `/mcp`).
|
|
50
67
|
|
|
51
68
|
## Tools
|
|
52
69
|
|
|
53
|
-
**Market data:** `get_price`, `get_recent_trades`, `get_candles`, `get_funding_rates`, `get_open_interest`, `get_liquidations`, `get_fills`, `get_mark_prices`, `get_vault_operations`, `list_markets`, `get_markets_snapshot`
|
|
70
|
+
**Market data:** `get_price`, `get_recent_trades`, `get_candles`, `get_funding_rates`, `get_open_interest`, `get_liquidations`, `get_liquidation_summary`, `get_fills`, `get_mark_prices`, `get_vault_operations`, `list_markets`, `get_markets_snapshot`
|
|
71
|
+
|
|
72
|
+
**Market analytics:** `get_funding_stats`, `get_pnl_leaderboard`, `get_market_top_wallets`, `get_wallet_labels`, `get_liquidation_levels` and `get_vault_leaderboard` (these two need a Builder or Enterprise key)
|
|
54
73
|
|
|
55
|
-
**
|
|
74
|
+
**Signals:** `get_top_traders`, `get_market_leaders`, `get_early_movers`, `get_trader_profile`
|
|
56
75
|
|
|
57
76
|
**Wallet analytics:** `get_user_state`, `get_user_summary`, `get_user_pnl_series`, `get_user_funding`, `get_user_maker_taker`, `get_user_ledger`
|
|
58
77
|
|
|
@@ -66,8 +85,9 @@ Fill history covers a rolling 12 months. There is no order book, order status or
|
|
|
66
85
|
|
|
67
86
|
| Env var | Default |
|
|
68
87
|
|---|---|
|
|
69
|
-
| `IRONFLOW_API_KEY` |
|
|
88
|
+
| `IRONFLOW_API_KEY` | optional; free key at [ironflow.sh/key](https://ironflow.sh/key) |
|
|
70
89
|
| `IRONFLOW_API_URL` | `https://api.ironflow.sh` |
|
|
90
|
+
| `PORT` (HTTP server) | `8080` |
|
|
71
91
|
|
|
72
92
|
## Links
|
|
73
93
|
|
package/build/api.d.ts
CHANGED
|
@@ -2,7 +2,9 @@ export declare class IronflowAPI {
|
|
|
2
2
|
private baseUrl;
|
|
3
3
|
private apiKey?;
|
|
4
4
|
private source;
|
|
5
|
-
|
|
5
|
+
private userAgent;
|
|
6
|
+
private forwardedFor?;
|
|
7
|
+
constructor(baseUrl?: string, apiKey?: string, source?: string, version?: string, forwardedFor?: string);
|
|
6
8
|
private headers;
|
|
7
9
|
private apiError;
|
|
8
10
|
get(path: string, params?: Record<string, string>): Promise<unknown>;
|
|
@@ -15,9 +17,7 @@ export declare class IronflowAPI {
|
|
|
15
17
|
getFills(address: string, market?: string, limit?: string): Promise<unknown>;
|
|
16
18
|
getMarkPrices(market: string): Promise<unknown>;
|
|
17
19
|
getVaultOperations(vault?: string, address?: string, limit?: string): Promise<unknown>;
|
|
18
|
-
getNetFlows(interval?: string, limit?: string): Promise<unknown>;
|
|
19
20
|
getLiquidationLevels(market: string, bucket_size?: string): Promise<unknown>;
|
|
20
|
-
getOrderFlow(market?: string): Promise<unknown>;
|
|
21
21
|
getVaultLeaderboard(limit?: string): Promise<unknown>;
|
|
22
22
|
getFundingStats(market: string, interval?: string, limit?: string): Promise<unknown>;
|
|
23
23
|
getUserState(address: string): Promise<unknown>;
|
package/build/api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAKA,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/build/api.js
CHANGED
|
@@ -5,19 +5,28 @@ export class IronflowAPI {
|
|
|
5
5
|
baseUrl;
|
|
6
6
|
apiKey;
|
|
7
7
|
source;
|
|
8
|
-
|
|
8
|
+
userAgent;
|
|
9
|
+
forwardedFor;
|
|
10
|
+
// forwardedFor is set only by the hosted HTTP server: it passes the MCP
|
|
11
|
+
// client's IP on so keyless rate limits apply per caller, not per server.
|
|
12
|
+
constructor(baseUrl = DEFAULT_BASE_URL, apiKey, source = DEFAULT_SOURCE, version = "unknown", forwardedFor) {
|
|
9
13
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
10
14
|
this.apiKey = apiKey;
|
|
11
15
|
this.source = source;
|
|
16
|
+
this.userAgent = `ironflow-mcp/${version}`;
|
|
17
|
+
this.forwardedFor = forwardedFor;
|
|
12
18
|
}
|
|
13
19
|
headers() {
|
|
14
20
|
const h = {
|
|
15
21
|
"Content-Type": "application/json",
|
|
16
|
-
"User-Agent":
|
|
22
|
+
"User-Agent": this.userAgent,
|
|
17
23
|
};
|
|
18
24
|
if (this.apiKey) {
|
|
19
25
|
h["Authorization"] = `Bearer ${this.apiKey}`;
|
|
20
26
|
}
|
|
27
|
+
if (this.forwardedFor) {
|
|
28
|
+
h["X-Forwarded-For"] = this.forwardedFor;
|
|
29
|
+
}
|
|
21
30
|
return h;
|
|
22
31
|
}
|
|
23
32
|
async apiError(res) {
|
|
@@ -97,18 +106,9 @@ export class IronflowAPI {
|
|
|
97
106
|
return this.get("/v1/vault-operations", params);
|
|
98
107
|
}
|
|
99
108
|
// ─── Analytics ────────────────────────────────────────────────────────
|
|
100
|
-
async getNetFlows(interval = "1d", limit = "7") {
|
|
101
|
-
return this.get("/v1/analytics/net-flows", { interval, limit });
|
|
102
|
-
}
|
|
103
109
|
async getLiquidationLevels(market, bucket_size = "100") {
|
|
104
110
|
return this.get("/v1/analytics/liquidation-levels", { market, bucket_size });
|
|
105
111
|
}
|
|
106
|
-
async getOrderFlow(market = "") {
|
|
107
|
-
const params = {};
|
|
108
|
-
if (market)
|
|
109
|
-
params.market = market;
|
|
110
|
-
return this.get("/v1/analytics/order-flow", params);
|
|
111
|
-
}
|
|
112
112
|
async getVaultLeaderboard(limit = "10") {
|
|
113
113
|
return this.get("/v1/analytics/vault-leaderboard", { limit });
|
|
114
114
|
}
|
package/build/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAE/E,MAAM,gBAAgB,GAAG,yBAAyB,CAAC;AACnD,MAAM,cAAc,GAAG,aAAa,CAAC;AAErC,MAAM,OAAO,WAAW;IACd,OAAO,CAAS;IAChB,MAAM,CAAU;IAChB,MAAM,CAAS;
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"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"}
|
package/build/http.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":""}
|
package/build/http.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Ironflow MCP Server (Streamable HTTP): the hosted endpoint behind
|
|
3
|
+
// https://mcp.ironflow.sh/mcp. Stateless: every POST builds a fresh server
|
|
4
|
+
// and transport, so any replica can answer any request.
|
|
5
|
+
//
|
|
6
|
+
// Connect without installing anything:
|
|
7
|
+
// claude mcp add --transport http ironflow https://mcp.ironflow.sh/mcp
|
|
8
|
+
//
|
|
9
|
+
// A key is optional. Send it as "Authorization: Bearer if_..." or, for
|
|
10
|
+
// clients that cannot set headers, as ?key=if_... on the URL.
|
|
11
|
+
//
|
|
12
|
+
// Environment:
|
|
13
|
+
// PORT listen port (default 8080)
|
|
14
|
+
// IRONFLOW_API_URL REST API base (default https://api.ironflow.sh)
|
|
15
|
+
// FORWARD_CLIENT_IP "true" only behind a proxy that sets X-Forwarded-For
|
|
16
|
+
// to the real client IP; the IP is passed to the API so
|
|
17
|
+
// keyless limits apply per caller
|
|
18
|
+
import { createServer as createHttpServer } from "node:http";
|
|
19
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
20
|
+
import { IronflowAPI } from "./api.js";
|
|
21
|
+
import { clientIP, HttpError, readKey } from "./request.js";
|
|
22
|
+
import { createServer, packageVersion } from "./server.js";
|
|
23
|
+
const DEFAULT_PORT = 8080;
|
|
24
|
+
const MAX_BODY_BYTES = 1024 * 1024;
|
|
25
|
+
const MCP_PATH = "/mcp";
|
|
26
|
+
const INFO_URL = "https://ironflow.sh/api#mcp";
|
|
27
|
+
const port = Number(process.env.PORT) || DEFAULT_PORT;
|
|
28
|
+
const apiUrl = process.env.IRONFLOW_API_URL || "https://api.ironflow.sh";
|
|
29
|
+
const forwardClientIP = process.env.FORWARD_CLIENT_IP === "true";
|
|
30
|
+
const version = packageVersion();
|
|
31
|
+
// setCors allows browser-based MCP clients (inspectors, web agents). No
|
|
32
|
+
// cookies are involved, so a wildcard origin is safe.
|
|
33
|
+
function setCors(res) {
|
|
34
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
35
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
36
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID");
|
|
37
|
+
res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id");
|
|
38
|
+
}
|
|
39
|
+
function sendJSON(res, status, body) {
|
|
40
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
41
|
+
res.end(JSON.stringify(body));
|
|
42
|
+
}
|
|
43
|
+
// sendRPCError answers with a JSON-RPC error object, the shape MCP clients
|
|
44
|
+
// know how to display.
|
|
45
|
+
function sendRPCError(res, status, message) {
|
|
46
|
+
sendJSON(res, status, { jsonrpc: "2.0", error: { code: -32000, message }, id: null });
|
|
47
|
+
}
|
|
48
|
+
async function readBody(req) {
|
|
49
|
+
const chunks = [];
|
|
50
|
+
let size = 0;
|
|
51
|
+
for await (const chunk of req) {
|
|
52
|
+
size += chunk.length;
|
|
53
|
+
if (size > MAX_BODY_BYTES)
|
|
54
|
+
throw new HttpError(413, "Request body too large");
|
|
55
|
+
chunks.push(chunk);
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf-8"));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
throw new HttpError(400, "Request body is not valid JSON");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// describeRPC names what a request did for the access log, without keys,
|
|
65
|
+
// IPs or arguments.
|
|
66
|
+
function describeRPC(body) {
|
|
67
|
+
const msgs = Array.isArray(body) ? body : [body];
|
|
68
|
+
return msgs
|
|
69
|
+
.map((m) => {
|
|
70
|
+
const msg = m;
|
|
71
|
+
return msg.method === "tools/call" ? `tools/call:${msg.params?.name}` : msg.method ?? "?";
|
|
72
|
+
})
|
|
73
|
+
.join(",");
|
|
74
|
+
}
|
|
75
|
+
async function handleMCP(req, res, url) {
|
|
76
|
+
const started = Date.now();
|
|
77
|
+
const key = readKey(req, url);
|
|
78
|
+
const body = await readBody(req);
|
|
79
|
+
const api = new IronflowAPI(apiUrl, key, undefined, `${version}-hosted`, clientIP(req, forwardClientIP));
|
|
80
|
+
const server = createServer(api, version);
|
|
81
|
+
const transport = new StreamableHTTPServerTransport({
|
|
82
|
+
sessionIdGenerator: undefined,
|
|
83
|
+
enableJsonResponse: true,
|
|
84
|
+
});
|
|
85
|
+
res.on("close", () => {
|
|
86
|
+
void transport.close();
|
|
87
|
+
void server.close();
|
|
88
|
+
console.log(JSON.stringify({ msg: "mcp", rpc: describeRPC(body), keyed: Boolean(key), status: res.statusCode, ms: Date.now() - started }));
|
|
89
|
+
});
|
|
90
|
+
await server.connect(transport);
|
|
91
|
+
await transport.handleRequest(req, res, body);
|
|
92
|
+
}
|
|
93
|
+
async function route(req, res) {
|
|
94
|
+
const url = new URL(req.url ?? "/", "http://localhost");
|
|
95
|
+
setCors(res);
|
|
96
|
+
if (req.method === "OPTIONS") {
|
|
97
|
+
res.writeHead(204).end();
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (url.pathname === "/healthz") {
|
|
101
|
+
sendJSON(res, 200, { status: "ok", version });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (url.pathname === "/" && (req.method === "GET" || req.method === "HEAD")) {
|
|
105
|
+
res.writeHead(302, { Location: INFO_URL }).end();
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (url.pathname !== MCP_PATH) {
|
|
109
|
+
sendJSON(res, 404, { error: "Not found. The MCP endpoint is /mcp" });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (req.method !== "POST") {
|
|
113
|
+
// Stateless server: no standalone SSE stream and no sessions to delete.
|
|
114
|
+
res.setHeader("Allow", "POST, OPTIONS");
|
|
115
|
+
sendRPCError(res, 405, "Method not allowed: this server is stateless, use POST");
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
await handleMCP(req, res, url);
|
|
119
|
+
}
|
|
120
|
+
const httpServer = createHttpServer((req, res) => {
|
|
121
|
+
route(req, res).catch((err) => {
|
|
122
|
+
if (res.headersSent) {
|
|
123
|
+
res.end();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (err instanceof HttpError) {
|
|
127
|
+
sendRPCError(res, err.status, err.message);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
console.error(JSON.stringify({ msg: "mcp handler failed", error: String(err) }));
|
|
131
|
+
sendRPCError(res, 500, "Internal server error");
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
httpServer.listen(port, () => {
|
|
135
|
+
console.log(JSON.stringify({ msg: "ironflow mcp http listening", port, version, apiUrl, forwardClientIP }));
|
|
136
|
+
});
|
|
137
|
+
// Graceful shutdown: stop accepting, let in-flight requests finish.
|
|
138
|
+
for (const signal of ["SIGTERM", "SIGINT"]) {
|
|
139
|
+
process.on(signal, () => {
|
|
140
|
+
httpServer.close(() => process.exit(0));
|
|
141
|
+
setTimeout(() => process.exit(0), 10_000).unref();
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/build/index.js
CHANGED
|
@@ -1,81 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Ironflow MCP Server: read-only Hyperliquid data for AI agents.
|
|
2
|
+
// Ironflow MCP Server (stdio): read-only Hyperliquid data for AI agents.
|
|
3
3
|
//
|
|
4
4
|
// Usage:
|
|
5
5
|
// IRONFLOW_API_KEY=if_xxx npx -y @ironflowsh/mcp
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import { fileURLToPath } from "node:url";
|
|
12
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
7
|
+
// The key is optional: keyless calls get 10 requests per minute and 24 hours
|
|
8
|
+
// of history; a free key from https://ironflow.sh/key gives 60 and 30 days.
|
|
9
|
+
// No install needed at all with the hosted server:
|
|
10
|
+
// claude mcp add --transport http ironflow https://mcp.ironflow.sh/mcp
|
|
13
11
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
14
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
15
12
|
import { IronflowAPI } from "./api.js";
|
|
16
|
-
import {
|
|
13
|
+
import { createServer, packageVersion } from "./server.js";
|
|
17
14
|
const apiUrl = process.env.IRONFLOW_API_URL || "https://api.ironflow.sh";
|
|
18
15
|
const apiKey = process.env.IRONFLOW_API_KEY;
|
|
19
16
|
if (!apiKey) {
|
|
20
17
|
// stderr: stdout carries the MCP protocol.
|
|
21
|
-
console.error("IRONFLOW_API_KEY is not set
|
|
18
|
+
console.error("IRONFLOW_API_KEY is not set: running keyless (10 requests per minute, 24 hours of history). Free key for more: https://ironflow.sh/key");
|
|
22
19
|
}
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
// drifts on every release.
|
|
27
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
28
|
-
let pkgVersion = "unknown";
|
|
29
|
-
try {
|
|
30
|
-
const pkgRaw = readFileSync(join(here, "..", "package.json"), "utf-8");
|
|
31
|
-
pkgVersion = JSON.parse(pkgRaw).version ?? "unknown";
|
|
32
|
-
}
|
|
33
|
-
catch {
|
|
34
|
-
// Fall through with "unknown" — the server still functions; only
|
|
35
|
-
// the version string in initialize() is affected.
|
|
36
|
-
}
|
|
37
|
-
const server = new Server({
|
|
38
|
-
name: "ironflow",
|
|
39
|
-
version: pkgVersion,
|
|
40
|
-
}, {
|
|
41
|
-
capabilities: {
|
|
42
|
-
tools: {},
|
|
43
|
-
},
|
|
44
|
-
});
|
|
45
|
-
// List all available tools.
|
|
46
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
47
|
-
return {
|
|
48
|
-
tools: tools.map((t) => ({
|
|
49
|
-
name: t.name,
|
|
50
|
-
description: t.description,
|
|
51
|
-
inputSchema: t.inputSchema,
|
|
52
|
-
})),
|
|
53
|
-
};
|
|
54
|
-
});
|
|
55
|
-
// Handle tool calls.
|
|
56
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
57
|
-
const { name, arguments: args } = request.params;
|
|
58
|
-
const tool = tools.find((t) => t.name === name);
|
|
59
|
-
if (!tool) {
|
|
60
|
-
return {
|
|
61
|
-
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
62
|
-
isError: true,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
try {
|
|
66
|
-
const result = await tool.handler(args ?? {}, api);
|
|
67
|
-
return {
|
|
68
|
-
content: [{ type: "text", text: result }],
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
catch (error) {
|
|
72
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
73
|
-
return {
|
|
74
|
-
content: [{ type: "text", text: `Error: ${message}` }],
|
|
75
|
-
isError: true,
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
const transport = new StdioServerTransport();
|
|
80
|
-
await server.connect(transport);
|
|
20
|
+
const version = packageVersion();
|
|
21
|
+
const server = createServer(new IronflowAPI(apiUrl, apiKey, undefined, version), version);
|
|
22
|
+
await server.connect(new StdioServerTransport());
|
|
81
23
|
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,yEAAyE;AACzE,EAAE;AACF,SAAS;AACT,mDAAmD;AACnD,EAAE;AACF,6EAA6E;AAC7E,4EAA4E;AAC5E,mDAAmD;AACnD,yEAAyE;AAEzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE3D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,yBAAyB,CAAC;AACzE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAE5C,IAAI,CAAC,MAAM,EAAE,CAAC;IACZ,2CAA2C;IAC3C,OAAO,CAAC,KAAK,CACX,wIAAwI,CACzI,CAAC;AACJ,CAAC;AAED,MAAM,OAAO,GAAG,cAAc,EAAE,CAAC;AACjC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;AAC1F,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { IronflowAPI } from "./api.js";
|
|
2
|
+
export declare const MAX_SUMMARY_MINUTES = 240;
|
|
3
|
+
export declare const MAX_SUMMARY_PAGES = 8;
|
|
4
|
+
export interface LiquidationSummary {
|
|
5
|
+
from: number;
|
|
6
|
+
to: number;
|
|
7
|
+
market: string | null;
|
|
8
|
+
count: number;
|
|
9
|
+
notional_usd: number;
|
|
10
|
+
longs_liquidated_usd: number;
|
|
11
|
+
shorts_liquidated_usd: number;
|
|
12
|
+
by_market: {
|
|
13
|
+
market: string;
|
|
14
|
+
count: number;
|
|
15
|
+
notional_usd: number;
|
|
16
|
+
}[];
|
|
17
|
+
largest: {
|
|
18
|
+
market: string;
|
|
19
|
+
side: "long" | "short";
|
|
20
|
+
notional_usd: number;
|
|
21
|
+
price: number;
|
|
22
|
+
address: string;
|
|
23
|
+
timestamp: number;
|
|
24
|
+
} | null;
|
|
25
|
+
complete: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare function summarizeLiquidations(api: IronflowAPI, minutes: number, market: string, now?: number): Promise<LiquidationSummary>;
|
|
28
|
+
//# sourceMappingURL=liquidations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liquidations.d.ts","sourceRoot":"","sources":["../src/liquidations.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAE5C,eAAO,MAAM,mBAAmB,MAAM,CAAC;AACvC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAmBnC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAS,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACrE,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACpI,QAAQ,EAAE,OAAO,CAAC;CACnB;AAOD,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,WAAW,EAChB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,GAAG,SAAa,GACf,OAAO,CAAC,kBAAkB,CAAC,CA+D7B"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Liquidation summary across all Hyperliquid markets. The REST feed returns
|
|
2
|
+
// raw rows (up to 1000 per page); an agent asking "who got liquidated in the
|
|
3
|
+
// last hour" needs totals, so the MCP pages through and aggregates.
|
|
4
|
+
export const MAX_SUMMARY_MINUTES = 240; // API cap for queries without a market
|
|
5
|
+
export const MAX_SUMMARY_PAGES = 8;
|
|
6
|
+
const PAGE_SIZE = "1000";
|
|
7
|
+
const TOP_MARKETS = 10;
|
|
8
|
+
const round = (n) => Math.round(n * 100) / 100;
|
|
9
|
+
// summarizeLiquidations fetches every liquidation in the window (up to
|
|
10
|
+
// MAX_SUMMARY_PAGES pages) and returns totals. complete=false means the page
|
|
11
|
+
// cap was hit and the totals are a lower bound.
|
|
12
|
+
export async function summarizeLiquidations(api, minutes, market, now = Date.now()) {
|
|
13
|
+
const from = now - minutes * 60_000;
|
|
14
|
+
const byMarket = new Map();
|
|
15
|
+
let count = 0;
|
|
16
|
+
let longs = 0;
|
|
17
|
+
let shorts = 0;
|
|
18
|
+
let largest = null;
|
|
19
|
+
let cursor = "";
|
|
20
|
+
let complete = false;
|
|
21
|
+
for (let page = 0; page < MAX_SUMMARY_PAGES; page++) {
|
|
22
|
+
const params = { from: String(from), to: String(now), limit: PAGE_SIZE };
|
|
23
|
+
if (market)
|
|
24
|
+
params.market = market;
|
|
25
|
+
if (cursor)
|
|
26
|
+
params.cursor = cursor;
|
|
27
|
+
const resp = (await api.get("/v1/liquidations", params));
|
|
28
|
+
for (const row of resp.data ?? []) {
|
|
29
|
+
const notional = Number(row.price) * Number(row.size);
|
|
30
|
+
if (!Number.isFinite(notional))
|
|
31
|
+
continue;
|
|
32
|
+
const name = row.display_symbol || row.market || "?";
|
|
33
|
+
const isLong = row.side === "sell";
|
|
34
|
+
count++;
|
|
35
|
+
if (isLong)
|
|
36
|
+
longs += notional;
|
|
37
|
+
else
|
|
38
|
+
shorts += notional;
|
|
39
|
+
const agg = byMarket.get(name) ?? { count: 0, notional: 0 };
|
|
40
|
+
agg.count++;
|
|
41
|
+
agg.notional += notional;
|
|
42
|
+
byMarket.set(name, agg);
|
|
43
|
+
if (!largest || notional > largest.notional_usd) {
|
|
44
|
+
largest = {
|
|
45
|
+
market: name,
|
|
46
|
+
side: isLong ? "long" : "short",
|
|
47
|
+
notional_usd: round(notional),
|
|
48
|
+
price: Number(row.price),
|
|
49
|
+
address: row.address,
|
|
50
|
+
timestamp: row.timestamp,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const next = resp.pagination?.next_cursor;
|
|
55
|
+
if (!resp.pagination?.has_more || !next) {
|
|
56
|
+
complete = true;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
cursor = next;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
from,
|
|
63
|
+
to: now,
|
|
64
|
+
market: market || null,
|
|
65
|
+
count,
|
|
66
|
+
notional_usd: round(longs + shorts),
|
|
67
|
+
longs_liquidated_usd: round(longs),
|
|
68
|
+
shorts_liquidated_usd: round(shorts),
|
|
69
|
+
by_market: [...byMarket.entries()]
|
|
70
|
+
.sort((a, b) => b[1].notional - a[1].notional)
|
|
71
|
+
.slice(0, TOP_MARKETS)
|
|
72
|
+
.map(([m, a]) => ({ market: m, count: a.count, notional_usd: round(a.notional) })),
|
|
73
|
+
largest,
|
|
74
|
+
complete,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=liquidations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"liquidations.js","sourceRoot":"","sources":["../src/liquidations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { IncomingMessage } from "node:http";
|
|
2
|
+
export declare class HttpError extends Error {
|
|
3
|
+
readonly status: number;
|
|
4
|
+
constructor(status: number, message: string);
|
|
5
|
+
}
|
|
6
|
+
export declare function readKey(req: IncomingMessage, url: URL): string | undefined;
|
|
7
|
+
export declare function clientIP(req: IncomingMessage, trustProxy: boolean): string | undefined;
|
|
8
|
+
//# sourceMappingURL=request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../src/request.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAKjD,qBAAa,SAAU,SAAQ,KAAK;IAEhC,QAAQ,CAAC,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM;CAIlB;AAKD,wBAAgB,OAAO,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,GAAG,GAAG,MAAM,GAAG,SAAS,CAW1E;AAID,wBAAgB,QAAQ,CAAC,GAAG,EAAE,eAAe,EAAE,UAAU,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAKtF"}
|