flash-trade-mcp 0.4.0 → 0.4.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/dist/index.js +64 -25
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -49275,7 +49275,24 @@ function formatPriceUsd(data) {
|
|
|
49275
49275
|
const exp = parseFloat(data.exponent);
|
|
49276
49276
|
if (isNaN(price) || isNaN(exp))
|
|
49277
49277
|
return "?";
|
|
49278
|
-
|
|
49278
|
+
const usd = price * Math.pow(10, exp);
|
|
49279
|
+
if (usd === 0)
|
|
49280
|
+
return "0.00";
|
|
49281
|
+
if (usd < 0.01)
|
|
49282
|
+
return usd.toPrecision(4);
|
|
49283
|
+
return usd.toFixed(2);
|
|
49284
|
+
}
|
|
49285
|
+
function formatCompactUsd(valueStr) {
|
|
49286
|
+
if (!valueStr)
|
|
49287
|
+
return "$?";
|
|
49288
|
+
const num = parseFloat(valueStr);
|
|
49289
|
+
if (isNaN(num))
|
|
49290
|
+
return `$${valueStr}`;
|
|
49291
|
+
if (num >= 1e6)
|
|
49292
|
+
return `$${(num / 1e6).toFixed(2)}M`;
|
|
49293
|
+
if (num >= 1000)
|
|
49294
|
+
return `$${(num / 1000).toFixed(1)}K`;
|
|
49295
|
+
return `$${num.toFixed(2)}`;
|
|
49279
49296
|
}
|
|
49280
49297
|
function buildCustodySymbolMap(poolData) {
|
|
49281
49298
|
const map3 = new Map;
|
|
@@ -49376,24 +49393,43 @@ Use get_pool with a pubkey for full details. Use get_pool_data for AUM and utili
|
|
|
49376
49393
|
});
|
|
49377
49394
|
}
|
|
49378
49395
|
|
|
49396
|
+
// src/sanitize.ts
|
|
49397
|
+
var zBool = exports_external.preprocess((v) => {
|
|
49398
|
+
if (typeof v === "string")
|
|
49399
|
+
return v === "true";
|
|
49400
|
+
return v;
|
|
49401
|
+
}, exports_external.boolean());
|
|
49402
|
+
function sanitizeError(e) {
|
|
49403
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
49404
|
+
return msg.replace(/\[[\d,\s]{20,}\]/g, "[REDACTED]").replace(/[0-9a-fA-F]{40,}/g, "[REDACTED]").replace(/[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{40,}/g, "[REDACTED]").replace(/[A-Za-z0-9+/]{40,}={0,2}/g, "[REDACTED]");
|
|
49405
|
+
}
|
|
49406
|
+
|
|
49379
49407
|
// src/tools/custodies.ts
|
|
49380
49408
|
function registerCustodyTools(server, client) {
|
|
49381
49409
|
server.registerTool("get_custodies", {
|
|
49382
|
-
description: "List all custody accounts (token vaults) across pools. Returns a compact summary with symbol,
|
|
49410
|
+
description: "List all custody accounts (token vaults) across pools. Returns a compact summary with symbol, pool, and pubkey. Use get_custody with a specific pubkey for full details (utilization, fees, limits)."
|
|
49383
49411
|
}, async () => {
|
|
49384
|
-
const
|
|
49412
|
+
const [custResult, poolResult] = await Promise.allSettled([
|
|
49413
|
+
client.getCustodies(),
|
|
49414
|
+
client.getPoolData()
|
|
49415
|
+
]);
|
|
49416
|
+
const custodies = custResult.status === "fulfilled" ? custResult.value : [];
|
|
49417
|
+
const custodyMap = poolResult.status === "fulfilled" ? buildCustodySymbolMap(poolResult.value) : new Map;
|
|
49418
|
+
if (custodies.length === 0) {
|
|
49419
|
+
const err = custResult.status === "rejected" ? `: ${sanitizeError(custResult.reason)}` : "";
|
|
49420
|
+
return { content: [{ type: "text", text: `No custody accounts found${err}` }] };
|
|
49421
|
+
}
|
|
49385
49422
|
const lines = [
|
|
49386
49423
|
`${custodies.length} custody accounts:
|
|
49387
49424
|
`,
|
|
49388
|
-
"Symbol |
|
|
49389
|
-
"
|
|
49425
|
+
"Symbol | Pool | Pubkey",
|
|
49426
|
+
"-----------|----------------|----------------------------------------------"
|
|
49390
49427
|
];
|
|
49391
49428
|
for (const c of custodies) {
|
|
49392
|
-
const
|
|
49393
|
-
const
|
|
49394
|
-
const
|
|
49395
|
-
|
|
49396
|
-
lines.push(`${symbol2} | ${mint} | ${c.pubkey}`);
|
|
49429
|
+
const info = custodyMap.get(c.pubkey);
|
|
49430
|
+
const symbol2 = (info?.symbol ?? "?").padEnd(10);
|
|
49431
|
+
const pool = (info?.pool ?? "?").padEnd(14);
|
|
49432
|
+
lines.push(`${symbol2} | ${pool} | ${c.pubkey}`);
|
|
49397
49433
|
}
|
|
49398
49434
|
lines.push(`
|
|
49399
49435
|
Use get_custody with a pubkey for full details (utilization, fees, limits).`);
|
|
@@ -49569,17 +49605,6 @@ Use get_pool_data with pool_pubkey for full custody stats.`);
|
|
|
49569
49605
|
});
|
|
49570
49606
|
}
|
|
49571
49607
|
|
|
49572
|
-
// src/sanitize.ts
|
|
49573
|
-
var zBool = exports_external.preprocess((v) => {
|
|
49574
|
-
if (typeof v === "string")
|
|
49575
|
-
return v === "true";
|
|
49576
|
-
return v;
|
|
49577
|
-
}, exports_external.boolean());
|
|
49578
|
-
function sanitizeError(e) {
|
|
49579
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
49580
|
-
return msg.replace(/\[[\d,\s]{20,}\]/g, "[REDACTED]").replace(/[0-9a-fA-F]{40,}/g, "[REDACTED]").replace(/[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{40,}/g, "[REDACTED]").replace(/[A-Za-z0-9+/]{40,}={0,2}/g, "[REDACTED]");
|
|
49581
|
-
}
|
|
49582
|
-
|
|
49583
49608
|
// src/tools/account-summary.ts
|
|
49584
49609
|
function registerAccountSummaryTool(server, client) {
|
|
49585
49610
|
server.registerTool("get_account_summary", {
|
|
@@ -49660,6 +49685,7 @@ function registerAccountSummaryTool(server, client) {
|
|
|
49660
49685
|
for (const w of warnings)
|
|
49661
49686
|
lines.push(` ${w}`);
|
|
49662
49687
|
}
|
|
49688
|
+
lines.push("Note: Data is cached ~15 seconds. Recently closed positions may still appear briefly.");
|
|
49663
49689
|
return { content: [{ type: "text", text: lines.join(`
|
|
49664
49690
|
`) }] };
|
|
49665
49691
|
});
|
|
@@ -49702,7 +49728,12 @@ function registerTradingOverviewTool(server, client) {
|
|
|
49702
49728
|
open: m.account.permissions.allow_open_position
|
|
49703
49729
|
};
|
|
49704
49730
|
}).sort((a, b) => a.pool.localeCompare(b.pool) || a.symbol.localeCompare(b.symbol) || a.side.localeCompare(b.side));
|
|
49731
|
+
const seen = new Set;
|
|
49705
49732
|
for (const m of enriched) {
|
|
49733
|
+
const key = `${m.symbol}-${m.side}`;
|
|
49734
|
+
if (seen.has(key))
|
|
49735
|
+
continue;
|
|
49736
|
+
seen.add(key);
|
|
49706
49737
|
let priceStr = "?";
|
|
49707
49738
|
if (prices) {
|
|
49708
49739
|
const priceData = prices[m.symbol];
|
|
@@ -49720,7 +49751,7 @@ function registerTradingOverviewTool(server, client) {
|
|
|
49720
49751
|
lines.push("---------------|----------------|-----------|--------");
|
|
49721
49752
|
for (const p of poolData.pools) {
|
|
49722
49753
|
const name = (p.poolName ?? "Unknown").padEnd(14);
|
|
49723
|
-
const aum =
|
|
49754
|
+
const aum = formatCompactUsd(p.lpStats?.totalPoolValueUsd).padEnd(14);
|
|
49724
49755
|
const lp = `$${p.lpStats?.lpPrice ?? "?"}`.padEnd(9);
|
|
49725
49756
|
const stable = `${p.lpStats?.stableCoinPercentage ?? "?"}%`;
|
|
49726
49757
|
lines.push(`${name} | ${aum} | ${lp} | ${stable}`);
|
|
@@ -57130,9 +57161,17 @@ Signature: ${signature2}` }],
|
|
|
57130
57161
|
} catch (e) {
|
|
57131
57162
|
const msg = sanitizeError(e);
|
|
57132
57163
|
const isBlockhashExpired = msg.includes("Blockhash not found") || msg.includes("block height exceeded");
|
|
57133
|
-
const
|
|
57164
|
+
const isSignerMismatch = msg.includes("Cannot sign with non signer key");
|
|
57165
|
+
let hint = "";
|
|
57166
|
+
if (isBlockhashExpired) {
|
|
57167
|
+
hint = `
|
|
57168
|
+
|
|
57169
|
+
The blockhash has expired (~60 seconds). Re-call the original transaction tool to get a fresh transaction, then call sign_and_send immediately.`;
|
|
57170
|
+
} else if (isSignerMismatch) {
|
|
57171
|
+
hint = `
|
|
57134
57172
|
|
|
57135
|
-
The
|
|
57173
|
+
The transaction was built for a different wallet than the local keypair. Re-call the transaction tool to get a fresh transaction, then sign immediately — blockhashes expire in ~60 seconds.`;
|
|
57174
|
+
}
|
|
57136
57175
|
return {
|
|
57137
57176
|
content: [{ type: "text", text: `Transaction send failed: ${msg}${hint}` }],
|
|
57138
57177
|
isError: true
|
|
@@ -57376,7 +57415,7 @@ try {
|
|
|
57376
57415
|
const client = new FlashApiClient(config2);
|
|
57377
57416
|
const server = new McpServer({
|
|
57378
57417
|
name: "flash-trade",
|
|
57379
|
-
version: "0.4.
|
|
57418
|
+
version: "0.4.1"
|
|
57380
57419
|
}, {
|
|
57381
57420
|
capabilities: {
|
|
57382
57421
|
tools: {},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flash-trade-mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "MCP server for Flash Trade — perpetual futures DEX on Solana. Provides AI agents with typed tools for trading, position management, and market data.",
|
|
5
5
|
"module": "src/index.ts",
|
|
6
6
|
"main": "dist/index.js",
|