suprafx-agent-sdk 0.3.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/LICENSE +21 -0
- package/README.md +452 -0
- package/dist/bin/suprafx-mcp.d.ts +15 -0
- package/dist/bin/suprafx-mcp.js +238 -0
- package/dist/bin/suprafx-mcp.js.map +1 -0
- package/dist/src/asset-registry.d.ts +61 -0
- package/dist/src/asset-registry.js +118 -0
- package/dist/src/asset-registry.js.map +1 -0
- package/dist/src/client.d.ts +227 -0
- package/dist/src/client.js +282 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/derive-ids.d.ts +112 -0
- package/dist/src/derive-ids.js +361 -0
- package/dist/src/derive-ids.js.map +1 -0
- package/dist/src/event-bcs.d.ts +341 -0
- package/dist/src/event-bcs.js +767 -0
- package/dist/src/event-bcs.js.map +1 -0
- package/dist/src/index.d.ts +26 -0
- package/dist/src/index.js +26 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/mcp/config.d.ts +32 -0
- package/dist/src/mcp/config.js +101 -0
- package/dist/src/mcp/config.js.map +1 -0
- package/dist/src/mcp/lifecycle.d.ts +109 -0
- package/dist/src/mcp/lifecycle.js +170 -0
- package/dist/src/mcp/lifecycle.js.map +1 -0
- package/dist/src/mcp/preflight.d.ts +36 -0
- package/dist/src/mcp/preflight.js +291 -0
- package/dist/src/mcp/preflight.js.map +1 -0
- package/dist/src/mcp/server.d.ts +20 -0
- package/dist/src/mcp/server.js +235 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/mcp/tools.d.ts +51 -0
- package/dist/src/mcp/tools.js +1022 -0
- package/dist/src/mcp/tools.js.map +1 -0
- package/dist/src/sign-event.d.ts +185 -0
- package/dist/src/sign-event.js +331 -0
- package/dist/src/sign-event.js.map +1 -0
- package/dist/src/signer.d.ts +89 -0
- package/dist/src/signer.js +226 -0
- package/dist/src/signer.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session preflight: the checks that decide whether it is safe to trade
|
|
3
|
+
* right now, run as a first-class MCP tool instead of living in prose.
|
|
4
|
+
*
|
|
5
|
+
* Every check answers with a status and, when it is not `ok`, the ACTION
|
|
6
|
+
* that clears it — so an agent can branch on the result instead of
|
|
7
|
+
* parsing a paragraph. Run it on connect, and again after any surprise.
|
|
8
|
+
*/
|
|
9
|
+
import { registeredAssetId, canonicalChain } from "../derive-ids.js";
|
|
10
|
+
/** A quote older than this must not be traded against. */
|
|
11
|
+
export const ORACLE_STALE_MS = 120_000;
|
|
12
|
+
export async function runPreflight(opts) {
|
|
13
|
+
const { client, signer, masterAddress, mode } = opts;
|
|
14
|
+
const checks = [];
|
|
15
|
+
const push = (c) => checks.push(c);
|
|
16
|
+
// ── 1. Venue reachable, and which chain is it ────────────────────
|
|
17
|
+
let chainOk = false;
|
|
18
|
+
try {
|
|
19
|
+
const ci = await client.getChainInfo();
|
|
20
|
+
chainOk = true;
|
|
21
|
+
push({
|
|
22
|
+
name: "venue_reachable",
|
|
23
|
+
status: "ok",
|
|
24
|
+
detail: `chain ${ci.chainId}, threshold ${ci.threshold}${ci.validatorCount ? ` of ${ci.validatorCount}` : ""}`,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
catch (e) {
|
|
28
|
+
push({
|
|
29
|
+
name: "venue_reachable",
|
|
30
|
+
status: "fail",
|
|
31
|
+
detail: msg(e),
|
|
32
|
+
action: "The venue did not answer. Stop, retry once, then report — do not trade.",
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
// ── 2. Is the VENUE advancing, or only the L1? ───────────────────
|
|
36
|
+
//
|
|
37
|
+
// A stalled venue batch while the L1 keeps living looks exactly like a
|
|
38
|
+
// healthy chain from a single read. Sample the batch height twice.
|
|
39
|
+
if (chainOk) {
|
|
40
|
+
try {
|
|
41
|
+
const a = await client.getCurrentBatch();
|
|
42
|
+
await new Promise((r) => setTimeout(r, 3_000));
|
|
43
|
+
const b = await client.getCurrentBatch();
|
|
44
|
+
if (b > a) {
|
|
45
|
+
push({
|
|
46
|
+
name: "venue_advancing",
|
|
47
|
+
status: "ok",
|
|
48
|
+
detail: `batch ${a} → ${b} in 3s`,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
push({
|
|
53
|
+
name: "venue_advancing",
|
|
54
|
+
status: "warn",
|
|
55
|
+
detail: `batch height did not move in 3s (still ${a})`,
|
|
56
|
+
action: "The venue may be batching slowly or stalled. Sample again before " +
|
|
57
|
+
"trading; if it stays flat, stop trading and report — writes will " +
|
|
58
|
+
"accept at ingress and never commit.",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
push({ name: "venue_advancing", status: "warn", detail: msg(e) });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// ── 3. Do the venue's own assets derive to REGISTERED ids? ───────
|
|
67
|
+
//
|
|
68
|
+
// `list_assets` returns short chain ids ("ethereum", "supra"); the
|
|
69
|
+
// AssetId derivation is keyed on canonical ones ("eth-mainnet"). If
|
|
70
|
+
// this check fails, every trade on that asset gate-rejects silently.
|
|
71
|
+
try {
|
|
72
|
+
const assets = await client.listAssets();
|
|
73
|
+
const bad = assets.filter((a) => !registeredAssetId(a.chain_id, a.asset_symbol));
|
|
74
|
+
if (assets.length === 0) {
|
|
75
|
+
push({
|
|
76
|
+
name: "assets_resolvable",
|
|
77
|
+
status: "fail",
|
|
78
|
+
detail: "list_assets returned nothing",
|
|
79
|
+
action: "Read path is broken. Reconnect, then report.",
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else if (bad.length === 0) {
|
|
83
|
+
push({
|
|
84
|
+
name: "assets_resolvable",
|
|
85
|
+
status: "ok",
|
|
86
|
+
detail: `${assets.length}/${assets.length} venue assets derive to registered ids`,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
push({
|
|
91
|
+
name: "assets_resolvable",
|
|
92
|
+
status: "warn",
|
|
93
|
+
detail: `${bad.length} of ${assets.length} not in the token registry: ${bad
|
|
94
|
+
.map((a) => `${canonicalChain(a.chain_id)}/${a.asset_symbol}`)
|
|
95
|
+
.join(", ")}`,
|
|
96
|
+
action: "Do not trade the unlisted assets — their derived id is a placeholder " +
|
|
97
|
+
"the validator gate rejects. Update suprafx-agent-sdk and report.",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
push({ name: "assets_resolvable", status: "warn", detail: msg(e) });
|
|
103
|
+
}
|
|
104
|
+
// ── 4. Oracle freshness ──────────────────────────────────────────
|
|
105
|
+
if (opts.pair) {
|
|
106
|
+
try {
|
|
107
|
+
const o = await client.getOracle(opts.pair);
|
|
108
|
+
if (o.conversionRate == null) {
|
|
109
|
+
push({
|
|
110
|
+
name: "oracle_fresh",
|
|
111
|
+
status: "fail",
|
|
112
|
+
detail: `no conversionRate for ${opts.pair}`,
|
|
113
|
+
action: "Do not quote this pair — you have no fair value.",
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
else if (o.ageMs != null && o.ageMs > ORACLE_STALE_MS) {
|
|
117
|
+
push({
|
|
118
|
+
name: "oracle_fresh",
|
|
119
|
+
status: "fail",
|
|
120
|
+
detail: `${opts.pair} quote is ${Math.round(o.ageMs / 1000)}s old (limit ${ORACLE_STALE_MS / 1000}s)`,
|
|
121
|
+
action: "Do not quote against a stale oracle. Wait for a fresh tick.",
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
push({
|
|
126
|
+
name: "oracle_fresh",
|
|
127
|
+
status: "ok",
|
|
128
|
+
detail: `${opts.pair} = ${o.conversionRate}${o.ageMs != null ? `, ${Math.round(o.ageMs / 1000)}s old` : ""}`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
catch (e) {
|
|
133
|
+
push({ name: "oracle_fresh", status: "warn", detail: msg(e) });
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
push({
|
|
138
|
+
name: "oracle_fresh",
|
|
139
|
+
status: "skipped",
|
|
140
|
+
detail: "no pair given — pass `pair` to check fair-value freshness",
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// ── 5. Custody: is a delegate key loaded, and is a master known? ──
|
|
144
|
+
if (!signer) {
|
|
145
|
+
push({
|
|
146
|
+
name: "custody",
|
|
147
|
+
status: "skipped",
|
|
148
|
+
detail: "read-only: no delegate key configured",
|
|
149
|
+
action: "Configure a delegate key to trade (see `get_setup_status`).",
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
push({
|
|
154
|
+
name: "custody",
|
|
155
|
+
status: "ok",
|
|
156
|
+
detail: `signing as delegate ${signer.addressHex}. This key CANNOT withdraw funds — withdrawals are master-signed.`,
|
|
157
|
+
});
|
|
158
|
+
if (!masterAddress) {
|
|
159
|
+
push({
|
|
160
|
+
name: "master_address_known",
|
|
161
|
+
status: "warn",
|
|
162
|
+
detail: "no master address configured — balance reads need it",
|
|
163
|
+
action: "Ask the operator for their master StarKey address and set " +
|
|
164
|
+
"SUPRAFX_MASTER_ADDRESS (or `masterAddress` in ~/.suprafx/config.json).",
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
push({
|
|
169
|
+
name: "master_address_known",
|
|
170
|
+
status: "ok",
|
|
171
|
+
detail: masterAddress,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// ── 6. Sequence: local counter vs chain ──────────────────────────
|
|
176
|
+
if (signer) {
|
|
177
|
+
try {
|
|
178
|
+
const chainSeq = BigInt(await client.getSequenceNumber(signer.addressHex));
|
|
179
|
+
const localSeq = signer.getNextSeq();
|
|
180
|
+
if (chainSeq === localSeq) {
|
|
181
|
+
push({
|
|
182
|
+
name: "sequence_in_sync",
|
|
183
|
+
status: "ok",
|
|
184
|
+
detail: `local and chain both expect seq ${localSeq}`,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
push({
|
|
189
|
+
name: "sequence_in_sync",
|
|
190
|
+
status: "fail",
|
|
191
|
+
detail: `local seq ${localSeq}, chain expects ${chainSeq}`,
|
|
192
|
+
action: "seq_desync — reconnect the MCP server to re-anchor. Until then " +
|
|
193
|
+
"writes accept at ingress and are silently dropped as replays.",
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch (e) {
|
|
198
|
+
push({ name: "sequence_in_sync", status: "warn", detail: msg(e) });
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// ── 7. Funded? And is anything already locked? ───────────────────
|
|
202
|
+
if (masterAddress) {
|
|
203
|
+
try {
|
|
204
|
+
const balances = await client.getBalances(masterAddress);
|
|
205
|
+
const funded = balances.filter((b) => b.total > 0);
|
|
206
|
+
const locked = balances.filter((b) => (b.locked_in_rfq ?? 0) > 0 || (b.locked_in_orders ?? 0) > 0);
|
|
207
|
+
if (funded.length === 0) {
|
|
208
|
+
push({
|
|
209
|
+
name: "funded",
|
|
210
|
+
status: "warn",
|
|
211
|
+
detail: "master has no balances",
|
|
212
|
+
action: "Deposit from the dApp (operator step). A brand-new wallet's first " +
|
|
213
|
+
"deposit can take minutes to credit — wait and re-check, do not loop.",
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
push({
|
|
218
|
+
name: "funded",
|
|
219
|
+
status: "ok",
|
|
220
|
+
detail: funded
|
|
221
|
+
.map((b) => `${b.asset}: ${b.available} available / ${b.total} total`)
|
|
222
|
+
.join("; "),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
if (locked.length > 0) {
|
|
226
|
+
push({
|
|
227
|
+
name: "existing_locks",
|
|
228
|
+
status: "warn",
|
|
229
|
+
detail: locked
|
|
230
|
+
.map((b) => `${b.asset}: ${b.locked_in_rfq} locked_in_rfq, ${b.locked_in_orders} locked_in_orders`)
|
|
231
|
+
.join("; "),
|
|
232
|
+
action: "Funds are already committed. Run `list_my_open_orders` to see which " +
|
|
233
|
+
"order each lock belongs to before assuming it is a ghost-lock.",
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch (e) {
|
|
238
|
+
push({ name: "funded", status: "warn", detail: msg(e) });
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// ── 8. Stale own RFQs still holding collateral ───────────────────
|
|
242
|
+
if (masterAddress) {
|
|
243
|
+
try {
|
|
244
|
+
const stale = [];
|
|
245
|
+
for (const status of ["open", "expired"]) {
|
|
246
|
+
const rows = await client.getOrderbook({ status, limit: 200 });
|
|
247
|
+
for (const r of rows) {
|
|
248
|
+
if (r.taker_address?.toLowerCase() !== masterAddress.toLowerCase())
|
|
249
|
+
continue;
|
|
250
|
+
const expired = status === "expired" ||
|
|
251
|
+
(r.expires_at ? Date.parse(r.expires_at) < Date.now() : false);
|
|
252
|
+
if (expired)
|
|
253
|
+
stale.push(`${r.id} (${r.pair}, ${status})`);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
push({
|
|
257
|
+
name: "stale_own_rfqs",
|
|
258
|
+
status: stale.length === 0 ? "ok" : "warn",
|
|
259
|
+
detail: stale.length === 0
|
|
260
|
+
? "no expired RFQs of yours are still listed"
|
|
261
|
+
: `${stale.length} expired RFQ(s) still listed: ${stale.join(", ")}`,
|
|
262
|
+
action: stale.length === 0
|
|
263
|
+
? undefined
|
|
264
|
+
: "Each may still hold collateral. `cancel_rfq` them, then re-read get_balances.",
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
catch (e) {
|
|
268
|
+
push({ name: "stale_own_rfqs", status: "warn", detail: msg(e) });
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const failures = checks.filter((c) => c.status === "fail");
|
|
272
|
+
const readPathOk = checks.some((c) => c.name === "venue_reachable" && c.status === "ok");
|
|
273
|
+
const readyToTrade = !!signer && failures.length === 0;
|
|
274
|
+
return {
|
|
275
|
+
ready_to_trade: readyToTrade,
|
|
276
|
+
read_path_ok: readPathOk,
|
|
277
|
+
mode,
|
|
278
|
+
checks,
|
|
279
|
+
summary: readyToTrade
|
|
280
|
+
? `Ready to trade in ${mode} mode. ${checks.filter((c) => c.status === "warn").length} warning(s).`
|
|
281
|
+
: !signer
|
|
282
|
+
? "Read-only: reads verified, no delegate key configured so nothing can move money."
|
|
283
|
+
: `NOT ready to trade — ${failures.length} failing check(s): ${failures
|
|
284
|
+
.map((c) => c.name)
|
|
285
|
+
.join(", ")}.`,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function msg(e) {
|
|
289
|
+
return e instanceof Error ? e.message : String(e);
|
|
290
|
+
}
|
|
291
|
+
//# sourceMappingURL=preflight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../../../src/mcp/preflight.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP server wiring. Translates the `@modelcontextprotocol/sdk` tool
|
|
3
|
+
* lifecycle into calls against our handlers in `./tools.ts`.
|
|
4
|
+
*
|
|
5
|
+
* Transport: stdio (default for Claude Desktop, Cursor, Continue).
|
|
6
|
+
* The client launches `suprafx-mcp` as a subprocess and pipes JSON-RPC
|
|
7
|
+
* over stdin/stdout. No network listener on this side.
|
|
8
|
+
*/
|
|
9
|
+
import { type GateMode } from "./tools.js";
|
|
10
|
+
export interface MCPServerOptions {
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
delegatePrivKeyHex?: string | null;
|
|
13
|
+
/** Operator's master address — balances and locks live there. */
|
|
14
|
+
masterAddress?: string | null;
|
|
15
|
+
/** `guarded` (default) requires per-call acknowledgement on money tools. */
|
|
16
|
+
mode?: GateMode;
|
|
17
|
+
/** Tool classes to expose: read / trade / cancel. */
|
|
18
|
+
groups?: Set<string>;
|
|
19
|
+
}
|
|
20
|
+
export declare function runMCPServer(opts?: MCPServerOptions): Promise<void>;
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP server wiring. Translates the `@modelcontextprotocol/sdk` tool
|
|
3
|
+
* lifecycle into calls against our handlers in `./tools.ts`.
|
|
4
|
+
*
|
|
5
|
+
* Transport: stdio (default for Claude Desktop, Cursor, Continue).
|
|
6
|
+
* The client launches `suprafx-mcp` as a subprocess and pipes JSON-RPC
|
|
7
|
+
* over stdin/stdout. No network listener on this side.
|
|
8
|
+
*/
|
|
9
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
10
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
12
|
+
import { SupraFxClient, SupraFxError } from "../client.js";
|
|
13
|
+
import { DelegateSigner } from "../signer.js";
|
|
14
|
+
import { allTools, findTool, ToolError, } from "./tools.js";
|
|
15
|
+
import { loadConfig } from "./config.js";
|
|
16
|
+
export async function runMCPServer(opts = {}) {
|
|
17
|
+
const client = new SupraFxClient({ baseUrl: opts.baseUrl });
|
|
18
|
+
let signer = null;
|
|
19
|
+
if (opts.delegatePrivKeyHex) {
|
|
20
|
+
signer = new DelegateSigner({
|
|
21
|
+
delegatePrivKeyHex: opts.delegatePrivKeyHex,
|
|
22
|
+
client,
|
|
23
|
+
});
|
|
24
|
+
// Anchor the signer's seq counter to chain at startup.
|
|
25
|
+
try {
|
|
26
|
+
await signer.loadSequenceFromChain();
|
|
27
|
+
}
|
|
28
|
+
catch (e) {
|
|
29
|
+
// Log to stderr; signer is still usable, just with seq=0.
|
|
30
|
+
process.stderr.write(`[suprafx-mcp] warning: loadSequenceFromChain failed: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const ctx = {
|
|
34
|
+
client,
|
|
35
|
+
signer,
|
|
36
|
+
masterAddress: opts.masterAddress ?? null,
|
|
37
|
+
mode: opts.mode ?? "guarded",
|
|
38
|
+
groups: opts.groups ?? new Set(["read", "trade", "cancel"]),
|
|
39
|
+
};
|
|
40
|
+
// HOT-RELOAD of the delegate key. The key in `~/.suprafx/config.json`
|
|
41
|
+
// (or env) can be rotated while this long-lived stdio server runs. Without
|
|
42
|
+
// this, the signer built above is frozen for the life of the process, so
|
|
43
|
+
// after a rotation `get_my_identity` reports the stale delegate and writes
|
|
44
|
+
// sign with a stale (possibly revoked / 0-cap) key — silently. We re-read
|
|
45
|
+
// the config before every tool request and rebuild the signer ONLY when the
|
|
46
|
+
// resolved delegate key actually changes (re-anchoring its chain sequence).
|
|
47
|
+
// Steady-state cost is one small file read + string compare per call.
|
|
48
|
+
let currentKey = opts.delegatePrivKeyHex ?? null;
|
|
49
|
+
let refreshing = null;
|
|
50
|
+
// Single-flight: collapse concurrent tool-call refreshes into one, so an
|
|
51
|
+
// interleaved rotation can't trigger redundant rebuilds / racing chain reads.
|
|
52
|
+
function refreshSigner() {
|
|
53
|
+
if (!refreshing) {
|
|
54
|
+
refreshing = doRefreshSigner().finally(() => {
|
|
55
|
+
refreshing = null;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return refreshing;
|
|
59
|
+
}
|
|
60
|
+
async function doRefreshSigner() {
|
|
61
|
+
const cfg = loadConfig();
|
|
62
|
+
// The master address can be filled in after the server started (the
|
|
63
|
+
// operator pastes it once they find it). Pick it up on every call —
|
|
64
|
+
// it is not secret and costs nothing to re-read.
|
|
65
|
+
if (cfg.masterAddress)
|
|
66
|
+
ctx.masterAddress = cfg.masterAddress;
|
|
67
|
+
if (cfg.delegatePrivKeyHex === currentKey)
|
|
68
|
+
return; // unchanged — fast path
|
|
69
|
+
const oldAddr = ctx.signer?.addressHex ?? "none";
|
|
70
|
+
if (cfg.delegatePrivKeyHex) {
|
|
71
|
+
const next = new DelegateSigner({
|
|
72
|
+
delegatePrivKeyHex: cfg.delegatePrivKeyHex,
|
|
73
|
+
client,
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
await next.loadSequenceFromChain();
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
// Anchoring the new delegate's chain sequence failed (network blip).
|
|
80
|
+
// Do NOT install a seq-0 signer — it would replay-drop trades
|
|
81
|
+
// silently — and do NOT advance currentKey. Go read-only and retry
|
|
82
|
+
// the rebuild+anchor on the next tool call. Fails closed: safer than
|
|
83
|
+
// signing with a stale/old key after the operator rotated.
|
|
84
|
+
ctx.signer = null;
|
|
85
|
+
process.stderr.write(`[suprafx-mcp] warning: anchoring rotated delegate failed (${e instanceof Error ? e.message : String(e)}); staying read-only, will retry on next call\n`);
|
|
86
|
+
return; // currentKey unchanged → retried next call
|
|
87
|
+
}
|
|
88
|
+
ctx.signer = next;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
ctx.signer = null; // delegate removed → back to read-only
|
|
92
|
+
}
|
|
93
|
+
currentKey = cfg.delegatePrivKeyHex;
|
|
94
|
+
process.stderr.write(`[suprafx-mcp] delegate refreshed from config: ${oldAddr} -> ${ctx.signer?.addressHex ?? "none"}\n`);
|
|
95
|
+
}
|
|
96
|
+
const server = new Server({ name: "suprafx", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
97
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
98
|
+
await refreshSigner();
|
|
99
|
+
return {
|
|
100
|
+
tools: allTools(!!ctx.signer, ctx.groups).map((t) => ({
|
|
101
|
+
name: t.name,
|
|
102
|
+
description: t.description,
|
|
103
|
+
inputSchema: t.inputSchema,
|
|
104
|
+
})),
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
108
|
+
await refreshSigner();
|
|
109
|
+
const hasSigner = !!ctx.signer;
|
|
110
|
+
const tool = findTool(req.params.name, hasSigner, ctx.groups);
|
|
111
|
+
if (!tool) {
|
|
112
|
+
// Distinguish "no such tool" from "the operator did not expose it" —
|
|
113
|
+
// different problems with different fixes.
|
|
114
|
+
const knownToSdk = findTool(req.params.name, true);
|
|
115
|
+
return mcpError(knownToSdk
|
|
116
|
+
? {
|
|
117
|
+
code: "TOOL_NOT_EXPOSED",
|
|
118
|
+
detail: `${req.params.name} exists but this server was launched with ` +
|
|
119
|
+
`--tools=${[...(ctx.groups ?? [])].join(",")}`,
|
|
120
|
+
remedy: "the OPERATOR must relaunch the server with the class you need",
|
|
121
|
+
}
|
|
122
|
+
: {
|
|
123
|
+
code: "UNKNOWN_TOOL",
|
|
124
|
+
detail: `no tool named ${req.params.name}`,
|
|
125
|
+
remedy: "call `tools/list` and use a name from it",
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
try {
|
|
129
|
+
const result = await tool.handler(req.params.arguments ?? {}, ctx);
|
|
130
|
+
if (isRejectedEnvelope(result)) {
|
|
131
|
+
return mcpError(envelopeError(result));
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
content: [
|
|
135
|
+
{
|
|
136
|
+
type: "text",
|
|
137
|
+
text: JSON.stringify(result, jsonReplacer, 2),
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
return mcpError(normalizeError(e));
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
const transport = new StdioServerTransport();
|
|
147
|
+
await server.connect(transport);
|
|
148
|
+
process.stderr.write(`[suprafx-mcp] connected (delegate=${ctx.signer?.addressHex ?? "none"}, ` +
|
|
149
|
+
`master=${ctx.masterAddress ?? "unset"}, mode=${ctx.signer ? ctx.mode : "read_only"}, ` +
|
|
150
|
+
`tools=${[...(ctx.groups ?? ["read", "trade", "cancel"])].join("+")}, base=${opts.baseUrl ?? "https://suprafx.ai"}, ` +
|
|
151
|
+
`hot-reload=on)\n`);
|
|
152
|
+
}
|
|
153
|
+
function isRejectedEnvelope(value) {
|
|
154
|
+
return typeof value === "object" && value !== null && "ok" in value && value.ok === false;
|
|
155
|
+
}
|
|
156
|
+
function envelopeError(result) {
|
|
157
|
+
const upstream = result.code ? `${result.code}: ` : "";
|
|
158
|
+
const detail = result.detail ?? "the venue rejected the signed envelope";
|
|
159
|
+
if (/sequence|replay|strict.next|high.water/i.test(`${result.code ?? ""} ${detail}`)) {
|
|
160
|
+
return {
|
|
161
|
+
code: "SEQUENCE_MISMATCH",
|
|
162
|
+
detail: upstream + detail,
|
|
163
|
+
remedy: "run `get_setup_status`, re-fetch the delegate sequence number, then retry",
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
return {
|
|
167
|
+
code: "ENVELOPE_REJECTED",
|
|
168
|
+
detail: upstream + detail,
|
|
169
|
+
remedy: "run `get_setup_status`, fix the reported policy or balance issue, then retry",
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Remedy sentence for each `SupraFxError.action`. The client layer
|
|
174
|
+
* classifies failures by CATEGORY (auth / rate_limit / seq_desync / …);
|
|
175
|
+
* this turns that category into the same `{code, detail, remedy}` shape
|
|
176
|
+
* every other error already uses, so an agent sees ONE envelope no
|
|
177
|
+
* matter which layer failed.
|
|
178
|
+
*/
|
|
179
|
+
const ACTION_REMEDY = {
|
|
180
|
+
authenticate: "this read needs an authorized caller — ask the operator; do not retry in a loop",
|
|
181
|
+
backoff: "back off exponentially and retry; do NOT loop",
|
|
182
|
+
fix_input: "correct the input named in detail, then retry",
|
|
183
|
+
reconnect: "reconnect the MCP server to re-anchor the delegate sequence, then retry",
|
|
184
|
+
configure_key: "configure the delegate key (`suprafx-mcp init` or SUPRAFX_DELEGATE_PRIV_HEX) and RECONNECT",
|
|
185
|
+
acknowledge: "re-send the identical call with `acknowledged: true`",
|
|
186
|
+
retry: "retry once; if it persists, report it",
|
|
187
|
+
report: "do NOT retry blindly — read state back (`get_balances`, `list_my_open_orders`) and report",
|
|
188
|
+
};
|
|
189
|
+
function normalizeError(e) {
|
|
190
|
+
if (e instanceof ToolError) {
|
|
191
|
+
return { code: e.code, detail: e.detail, remedy: e.remedy };
|
|
192
|
+
}
|
|
193
|
+
if (e instanceof SupraFxError) {
|
|
194
|
+
return {
|
|
195
|
+
code: e.code.toUpperCase(),
|
|
196
|
+
detail: e.message,
|
|
197
|
+
remedy: ACTION_REMEDY[e.action] ?? "run `get_setup_status`, then retry",
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
const detail = e instanceof Error ? e.message : String(e);
|
|
201
|
+
if (e instanceof TypeError ||
|
|
202
|
+
/fetch|network|timed? ?out|abort|ECONN|ENOTFOUND|GET \/api|POST \/api/i.test(detail)) {
|
|
203
|
+
return {
|
|
204
|
+
code: "NETWORK_FAILURE",
|
|
205
|
+
detail,
|
|
206
|
+
remedy: "run `get_setup_status`, verify SUPRAFX_BASE_URL and connectivity, then retry",
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
code: "TOOL_EXECUTION_FAILED",
|
|
211
|
+
detail,
|
|
212
|
+
remedy: "run `get_setup_status`, correct the tool inputs shown in detail, then retry",
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function mcpError(error) {
|
|
216
|
+
return {
|
|
217
|
+
isError: true,
|
|
218
|
+
content: [
|
|
219
|
+
{
|
|
220
|
+
type: "text",
|
|
221
|
+
text: JSON.stringify(error, null, 2),
|
|
222
|
+
},
|
|
223
|
+
],
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/** JSON.stringify replacer that handles BigInt and Uint8Array. */
|
|
227
|
+
function jsonReplacer(_key, value) {
|
|
228
|
+
if (typeof value === "bigint")
|
|
229
|
+
return value.toString();
|
|
230
|
+
if (value instanceof Uint8Array) {
|
|
231
|
+
return "0x" + Array.from(value, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
232
|
+
}
|
|
233
|
+
return value;
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool definitions + handlers for SupraFX.
|
|
3
|
+
*
|
|
4
|
+
* DESIGN RULE: everything an agent needs in order to trade safely lives
|
|
5
|
+
* in the TOOL CONTRACT — the description it reads before calling, the
|
|
6
|
+
* lifecycle field it gets back, the structured error it gets on failure.
|
|
7
|
+
* Nothing important is left to prose in a doc the agent may never fetch.
|
|
8
|
+
*
|
|
9
|
+
* Tools are split into three classes, selectable at launch
|
|
10
|
+
* (`--tools=read,cancel`):
|
|
11
|
+
* read — always available, cannot move money
|
|
12
|
+
* trade — opens or fills a position (submit_rfq, place_quote, accept_quote)
|
|
13
|
+
* cancel — releases a position (cancel_rfq, withdraw_quote)
|
|
14
|
+
*
|
|
15
|
+
* Reference: docs/INTEGRATING-AGENTS.md
|
|
16
|
+
*/
|
|
17
|
+
import type { SupraFxClient } from "../client.js";
|
|
18
|
+
import type { DelegateSigner } from "../signer.js";
|
|
19
|
+
export type ToolGroup = "read" | "trade" | "cancel";
|
|
20
|
+
export type GateMode = "guarded" | "autonomous";
|
|
21
|
+
export interface ToolContext {
|
|
22
|
+
client: SupraFxClient;
|
|
23
|
+
/** Present only when a delegate key is configured. */
|
|
24
|
+
signer: DelegateSigner | null;
|
|
25
|
+
/** The operator's master address, if known. Balances live here. */
|
|
26
|
+
masterAddress?: string | null;
|
|
27
|
+
/** `guarded` requires `acknowledged:true` on every money tool. */
|
|
28
|
+
mode?: GateMode;
|
|
29
|
+
/** Which tool classes this server was launched with. */
|
|
30
|
+
groups?: Set<string>;
|
|
31
|
+
}
|
|
32
|
+
export interface ToolDef {
|
|
33
|
+
name: string;
|
|
34
|
+
description: string;
|
|
35
|
+
inputSchema: object;
|
|
36
|
+
/** Requires a configured delegate key (write tool). */
|
|
37
|
+
requiresSigner: boolean;
|
|
38
|
+
/** Tool class, for launch-time selection. Defaults to read. */
|
|
39
|
+
group?: ToolGroup;
|
|
40
|
+
/** Money-moving: gated behind `acknowledged` in guarded mode. */
|
|
41
|
+
dangerous?: boolean;
|
|
42
|
+
handler: (args: any, ctx: ToolContext) => Promise<unknown>;
|
|
43
|
+
}
|
|
44
|
+
export declare function allTools(hasSigner: boolean, groups?: Set<string>): ToolDef[];
|
|
45
|
+
export declare function findTool(name: string, hasSigner: boolean, groups?: Set<string>): ToolDef | undefined;
|
|
46
|
+
export declare class ToolError extends Error {
|
|
47
|
+
readonly code: string;
|
|
48
|
+
readonly detail: string;
|
|
49
|
+
readonly remedy: string;
|
|
50
|
+
constructor(code: string, detail: string, remedy: string);
|
|
51
|
+
}
|