flash-trade-mcp 0.3.5 → 0.4.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/dist/index.js +214 -19
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -49236,7 +49236,7 @@ class FlashApiClient {
|
|
|
49236
49236
|
// src/tools/health.ts
|
|
49237
49237
|
function registerHealthTools(server, client) {
|
|
49238
49238
|
server.registerTool("health_check", {
|
|
49239
|
-
description: "
|
|
49239
|
+
description: "Verify Flash Trade API connectivity and status. Call this first before any other tool. Returns service status and account counts."
|
|
49240
49240
|
}, async () => {
|
|
49241
49241
|
const health = await client.getHealth();
|
|
49242
49242
|
const lines = [`Status: ${health.status}`];
|
|
@@ -49250,7 +49250,7 @@ function registerHealthTools(server, client) {
|
|
|
49250
49250
|
});
|
|
49251
49251
|
}
|
|
49252
49252
|
|
|
49253
|
-
// src/tools/
|
|
49253
|
+
// src/tools/shared/custody-map.ts
|
|
49254
49254
|
var VIRTUAL_CUSTODY_MAP = {
|
|
49255
49255
|
"6bthDsp8pcGBGKVKCKZjV5JfuSUNRo62RG4hQHj1u4CK": { symbol: "BNB", pool: "Crypto.1", maxLeverage: "60.00" },
|
|
49256
49256
|
A8SKWb3pwbFUtxLQhnpUTfy7CkxBpWGvTLYyJyWHCMWv: { symbol: "PYTH", pool: "Governance.1", maxLeverage: "60.00" },
|
|
@@ -49270,6 +49270,13 @@ var VIRTUAL_CUSTODY_MAP = {
|
|
|
49270
49270
|
RQNURQjDbq2Yah2udtFTNT7TjR15vsPV3oJNnwYher8: { symbol: "TSLA", pool: "Equity.1", maxLeverage: "12.00" },
|
|
49271
49271
|
ArnD1faZVVkkewX4HUSoDuht46egAtVvhDTFMJn3DkFo: { symbol: "SAMO", pool: "Community.3", maxLeverage: "50.00" }
|
|
49272
49272
|
};
|
|
49273
|
+
function formatPriceUsd(data) {
|
|
49274
|
+
const price = parseFloat(data.price);
|
|
49275
|
+
const exp = parseFloat(data.exponent);
|
|
49276
|
+
if (isNaN(price) || isNaN(exp))
|
|
49277
|
+
return "?";
|
|
49278
|
+
return (price * Math.pow(10, exp)).toFixed(2);
|
|
49279
|
+
}
|
|
49273
49280
|
function buildCustodySymbolMap(poolData) {
|
|
49274
49281
|
const map3 = new Map;
|
|
49275
49282
|
for (const pool of poolData.pools) {
|
|
@@ -49288,6 +49295,8 @@ function buildCustodySymbolMap(poolData) {
|
|
|
49288
49295
|
}
|
|
49289
49296
|
return map3;
|
|
49290
49297
|
}
|
|
49298
|
+
|
|
49299
|
+
// src/tools/markets.ts
|
|
49291
49300
|
function formatMarketsSummary(markets, custodyInfo) {
|
|
49292
49301
|
const lines = [
|
|
49293
49302
|
`${markets.length} markets available:
|
|
@@ -49317,7 +49326,7 @@ Use get_market with a pubkey for full details. Use get_prices for current oracle
|
|
|
49317
49326
|
}
|
|
49318
49327
|
function registerMarketTools(server, client) {
|
|
49319
49328
|
server.registerTool("get_markets", {
|
|
49320
|
-
description: "List all available perpetual futures markets
|
|
49329
|
+
description: "List all available perpetual futures markets. Returns a summary table with symbol, side, pool, max leverage, and pubkey. For a trading-ready view with prices, use get_trading_overview instead."
|
|
49321
49330
|
}, async () => {
|
|
49322
49331
|
const [markets, poolData] = await Promise.all([
|
|
49323
49332
|
client.getMarkets(),
|
|
@@ -49370,10 +49379,26 @@ Use get_pool with a pubkey for full details. Use get_pool_data for AUM and utili
|
|
|
49370
49379
|
// src/tools/custodies.ts
|
|
49371
49380
|
function registerCustodyTools(server, client) {
|
|
49372
49381
|
server.registerTool("get_custodies", {
|
|
49373
|
-
description: "List all custody accounts
|
|
49382
|
+
description: "List all custody accounts (token vaults) across pools. Returns a compact summary with symbol, mint, and pubkey. Use get_custody with a specific pubkey for full details (utilization, fees, limits)."
|
|
49374
49383
|
}, async () => {
|
|
49375
49384
|
const custodies = await client.getCustodies();
|
|
49376
|
-
|
|
49385
|
+
const lines = [
|
|
49386
|
+
`${custodies.length} custody accounts:
|
|
49387
|
+
`,
|
|
49388
|
+
"Symbol | Mint | Pubkey",
|
|
49389
|
+
"-----------|----------------------------------------------|----------------------------------------------"
|
|
49390
|
+
];
|
|
49391
|
+
for (const c of custodies) {
|
|
49392
|
+
const acct = c.account ?? {};
|
|
49393
|
+
const mintObj = typeof acct.mint === "object" ? acct.mint : null;
|
|
49394
|
+
const symbol2 = (acct.symbol ?? mintObj?.symbol ?? "?").toString().padEnd(10);
|
|
49395
|
+
const mint = (mintObj?.key ?? (typeof acct.mint === "string" ? acct.mint : "?")).toString().slice(0, 44).padEnd(44);
|
|
49396
|
+
lines.push(`${symbol2} | ${mint} | ${c.pubkey}`);
|
|
49397
|
+
}
|
|
49398
|
+
lines.push(`
|
|
49399
|
+
Use get_custody with a pubkey for full details (utilization, fees, limits).`);
|
|
49400
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
49401
|
+
`) }] };
|
|
49377
49402
|
});
|
|
49378
49403
|
server.registerTool("get_custody", {
|
|
49379
49404
|
description: "Get detailed custody information for a specific custody account. Includes utilization, fees, and limits.",
|
|
@@ -49434,7 +49459,7 @@ function formatEnrichedPosition(p) {
|
|
|
49434
49459
|
}
|
|
49435
49460
|
function registerPositionTools(server, client) {
|
|
49436
49461
|
server.registerTool("get_positions", {
|
|
49437
|
-
description: "List perpetual positions
|
|
49462
|
+
description: "List open perpetual positions. Without owner: returns all positions (large response). With owner: returns enriched positions with live PnL, leverage, and liquidation price. For a complete wallet overview, use get_account_summary instead.",
|
|
49438
49463
|
inputSchema: {
|
|
49439
49464
|
owner: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).optional().describe("Wallet pubkey to filter by. When provided, returns enriched positions with PnL, leverage, and liquidation price.")
|
|
49440
49465
|
}
|
|
@@ -49455,7 +49480,7 @@ ${text}` }] };
|
|
|
49455
49480
|
return { content: [{ type: "text", text: JSON.stringify(positions, null, 2) }] };
|
|
49456
49481
|
});
|
|
49457
49482
|
server.registerTool("get_position", {
|
|
49458
|
-
description: "Get a single position by its on-chain
|
|
49483
|
+
description: "Get a single position by its on-chain pubkey. Returns raw position data. For enriched data with PnL and leverage, use get_positions with owner or get_account_summary.",
|
|
49459
49484
|
inputSchema: { pubkey: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Position account pubkey") }
|
|
49460
49485
|
}, async ({ pubkey }) => {
|
|
49461
49486
|
const position = await client.getPosition(pubkey);
|
|
@@ -49480,7 +49505,7 @@ function formatEnrichedOrder(o) {
|
|
|
49480
49505
|
}
|
|
49481
49506
|
function registerOrderTools(server, client) {
|
|
49482
49507
|
server.registerTool("get_orders", {
|
|
49483
|
-
description: "List
|
|
49508
|
+
description: "List pending orders (limit, take-profit, stop-loss). With owner: returns enriched orders with computed trigger prices and sizes. Needed to find order_id (0-7) for edit_trigger_order or cancel_trigger_order.",
|
|
49484
49509
|
inputSchema: {
|
|
49485
49510
|
owner: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).optional().describe("Wallet pubkey to filter by. When provided, returns enriched orders.")
|
|
49486
49511
|
}
|
|
@@ -49555,6 +49580,165 @@ function sanitizeError(e) {
|
|
|
49555
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]");
|
|
49556
49581
|
}
|
|
49557
49582
|
|
|
49583
|
+
// src/tools/account-summary.ts
|
|
49584
|
+
function registerAccountSummaryTool(server, client) {
|
|
49585
|
+
server.registerTool("get_account_summary", {
|
|
49586
|
+
description: "Get a complete wallet overview: all open positions (with PnL), all pending orders (limit/TP/SL), and current prices for held markets. " + "Recommended first call when managing a specific wallet — replaces calling get_positions + get_orders + get_prices separately.",
|
|
49587
|
+
inputSchema: {
|
|
49588
|
+
owner: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Wallet pubkey")
|
|
49589
|
+
}
|
|
49590
|
+
}, async ({ owner }) => {
|
|
49591
|
+
const [posResult, ordResult, priceResult] = await Promise.allSettled([
|
|
49592
|
+
client.getOwnerPositions(owner),
|
|
49593
|
+
client.getOwnerOrders(owner),
|
|
49594
|
+
client.getPrices()
|
|
49595
|
+
]);
|
|
49596
|
+
const positions = posResult.status === "fulfilled" ? posResult.value : null;
|
|
49597
|
+
const orders = ordResult.status === "fulfilled" ? ordResult.value : null;
|
|
49598
|
+
const prices = priceResult.status === "fulfilled" ? priceResult.value : null;
|
|
49599
|
+
const lines = [`=== Account Summary for ${owner} ===
|
|
49600
|
+
`];
|
|
49601
|
+
const warnings = [];
|
|
49602
|
+
if (!positions)
|
|
49603
|
+
warnings.push(`Positions unavailable: ${sanitizeError(posResult.reason)}`);
|
|
49604
|
+
if (!orders)
|
|
49605
|
+
warnings.push(`Orders unavailable: ${sanitizeError(ordResult.reason)}`);
|
|
49606
|
+
if (!prices)
|
|
49607
|
+
warnings.push(`Prices unavailable: ${sanitizeError(priceResult.reason)}`);
|
|
49608
|
+
if (!positions) {
|
|
49609
|
+
lines.push(`Positions: unavailable
|
|
49610
|
+
`);
|
|
49611
|
+
} else if (positions.length === 0) {
|
|
49612
|
+
lines.push(`Positions: None
|
|
49613
|
+
`);
|
|
49614
|
+
} else {
|
|
49615
|
+
lines.push(`── ${positions.length} Position(s) ──`);
|
|
49616
|
+
for (const p of positions) {
|
|
49617
|
+
const pnl = p.pnlWithFeeUsdUi ? ` | PnL: $${p.pnlWithFeeUsdUi} (${p.pnlPercentageWithFee}%)` : "";
|
|
49618
|
+
lines.push(` ${p.sideUi} ${p.marketSymbol}: $${p.sizeUsdUi} @ $${p.entryPriceUi} (${p.leverageUi}x)${pnl}`);
|
|
49619
|
+
lines.push(` Key: ${p.key} | Liq: $${p.liquidationPriceUi}`);
|
|
49620
|
+
}
|
|
49621
|
+
lines.push("");
|
|
49622
|
+
}
|
|
49623
|
+
if (!orders) {
|
|
49624
|
+
lines.push(`Orders: unavailable
|
|
49625
|
+
`);
|
|
49626
|
+
} else if (orders.length === 0) {
|
|
49627
|
+
lines.push(`Orders: None
|
|
49628
|
+
`);
|
|
49629
|
+
} else {
|
|
49630
|
+
lines.push(`── Orders ──`);
|
|
49631
|
+
for (const o of orders) {
|
|
49632
|
+
for (const lo of o.limitOrders ?? []) {
|
|
49633
|
+
lines.push(` LIMIT ${lo.sideUi} ${lo.symbol}: $${lo.sizeUsdUi} @ $${lo.entryPriceUi} (${lo.leverageUi}x)`);
|
|
49634
|
+
}
|
|
49635
|
+
for (const tp of o.takeProfitOrders ?? []) {
|
|
49636
|
+
lines.push(` TP ${tp.sideUi} ${tp.symbol}: $${tp.sizeUsdUi} @ $${tp.triggerPriceUi}`);
|
|
49637
|
+
}
|
|
49638
|
+
for (const sl of o.stopLossOrders ?? []) {
|
|
49639
|
+
lines.push(` SL ${sl.sideUi} ${sl.symbol}: $${sl.sizeUsdUi} @ $${sl.triggerPriceUi}`);
|
|
49640
|
+
}
|
|
49641
|
+
}
|
|
49642
|
+
lines.push("");
|
|
49643
|
+
}
|
|
49644
|
+
if (positions && prices) {
|
|
49645
|
+
const marketSymbols = [...new Set(positions.map((p) => p.marketSymbol).filter((s) => !!s))];
|
|
49646
|
+
if (marketSymbols.length > 0) {
|
|
49647
|
+
lines.push("── Current Prices ──");
|
|
49648
|
+
for (const sym of marketSymbols) {
|
|
49649
|
+
const priceData = prices[sym];
|
|
49650
|
+
if (priceData) {
|
|
49651
|
+
const usd = formatPriceUsd(priceData);
|
|
49652
|
+
lines.push(` ${sym}: ${usd === "?" ? "price unavailable" : `$${usd}`}`);
|
|
49653
|
+
}
|
|
49654
|
+
}
|
|
49655
|
+
lines.push("");
|
|
49656
|
+
}
|
|
49657
|
+
}
|
|
49658
|
+
if (warnings.length > 0) {
|
|
49659
|
+
lines.push("── Warnings ──");
|
|
49660
|
+
for (const w of warnings)
|
|
49661
|
+
lines.push(` ${w}`);
|
|
49662
|
+
}
|
|
49663
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
49664
|
+
`) }] };
|
|
49665
|
+
});
|
|
49666
|
+
}
|
|
49667
|
+
|
|
49668
|
+
// src/tools/trading-overview.ts
|
|
49669
|
+
function registerTradingOverviewTool(server, client) {
|
|
49670
|
+
server.registerTool("get_trading_overview", {
|
|
49671
|
+
description: "Get a trading-ready market snapshot: all markets with current oracle prices, max leverage, and pool utilization. " + "Recommended first call when planning new trades — replaces calling get_markets + get_prices + get_pool_data separately."
|
|
49672
|
+
}, async () => {
|
|
49673
|
+
const [marketsResult, pricesResult, poolResult] = await Promise.allSettled([
|
|
49674
|
+
client.getMarkets(),
|
|
49675
|
+
client.getPrices(),
|
|
49676
|
+
client.getPoolData()
|
|
49677
|
+
]);
|
|
49678
|
+
const markets = marketsResult.status === "fulfilled" ? marketsResult.value : null;
|
|
49679
|
+
const prices = pricesResult.status === "fulfilled" ? pricesResult.value : null;
|
|
49680
|
+
const poolData = poolResult.status === "fulfilled" ? poolResult.value : null;
|
|
49681
|
+
const lines = [`=== Trading Overview ===
|
|
49682
|
+
`];
|
|
49683
|
+
const warnings = [];
|
|
49684
|
+
if (!markets)
|
|
49685
|
+
warnings.push(`Markets unavailable: ${sanitizeError(marketsResult.reason)}`);
|
|
49686
|
+
if (!prices)
|
|
49687
|
+
warnings.push(`Prices unavailable: ${sanitizeError(pricesResult.reason)}`);
|
|
49688
|
+
if (!poolData)
|
|
49689
|
+
warnings.push(`Pool data unavailable: ${sanitizeError(poolResult.reason)}`);
|
|
49690
|
+
if (markets) {
|
|
49691
|
+
const custodyInfo = poolData ? buildCustodySymbolMap(poolData) : new Map;
|
|
49692
|
+
lines.push("── Markets ──");
|
|
49693
|
+
lines.push("Symbol | Price | Side | Max Lev | Pool");
|
|
49694
|
+
lines.push("-----------|---------------|-------|---------|---------------");
|
|
49695
|
+
const enriched = markets.map((m) => {
|
|
49696
|
+
const info = custodyInfo.get(m.account.target_custody);
|
|
49697
|
+
return {
|
|
49698
|
+
symbol: info?.symbol ?? "UNKNOWN",
|
|
49699
|
+
pool: info?.pool ?? "?",
|
|
49700
|
+
maxLeverage: info?.maxLeverage ?? "?",
|
|
49701
|
+
side: m.account.side,
|
|
49702
|
+
open: m.account.permissions.allow_open_position
|
|
49703
|
+
};
|
|
49704
|
+
}).sort((a, b) => a.pool.localeCompare(b.pool) || a.symbol.localeCompare(b.symbol) || a.side.localeCompare(b.side));
|
|
49705
|
+
for (const m of enriched) {
|
|
49706
|
+
let priceStr = "?";
|
|
49707
|
+
if (prices) {
|
|
49708
|
+
const priceData = prices[m.symbol];
|
|
49709
|
+
if (priceData)
|
|
49710
|
+
priceStr = `$${formatPriceUsd(priceData)}`;
|
|
49711
|
+
}
|
|
49712
|
+
const status = m.open ? "" : " [CLOSED]";
|
|
49713
|
+
lines.push(`${m.symbol.padEnd(10)} | ${priceStr.padEnd(13)} | ${m.side.padEnd(5)} | ${m.maxLeverage.padEnd(7)} | ${m.pool}${status}`);
|
|
49714
|
+
}
|
|
49715
|
+
}
|
|
49716
|
+
if (poolData) {
|
|
49717
|
+
lines.push(`
|
|
49718
|
+
── Pool Utilization ──`);
|
|
49719
|
+
lines.push("Pool | AUM | LP Price | Stable%");
|
|
49720
|
+
lines.push("---------------|----------------|-----------|--------");
|
|
49721
|
+
for (const p of poolData.pools) {
|
|
49722
|
+
const name = (p.poolName ?? "Unknown").padEnd(14);
|
|
49723
|
+
const aum = `$${p.lpStats?.totalPoolValueUsd ?? "?"}`.padEnd(14);
|
|
49724
|
+
const lp = `$${p.lpStats?.lpPrice ?? "?"}`.padEnd(9);
|
|
49725
|
+
const stable = `${p.lpStats?.stableCoinPercentage ?? "?"}%`;
|
|
49726
|
+
lines.push(`${name} | ${aum} | ${lp} | ${stable}`);
|
|
49727
|
+
}
|
|
49728
|
+
}
|
|
49729
|
+
if (warnings.length > 0) {
|
|
49730
|
+
lines.push(`
|
|
49731
|
+
── Warnings ──`);
|
|
49732
|
+
for (const w of warnings)
|
|
49733
|
+
lines.push(` ${w}`);
|
|
49734
|
+
}
|
|
49735
|
+
lines.push(`
|
|
49736
|
+
Use open_position to trade. Use get_account_summary to check existing positions.`);
|
|
49737
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
49738
|
+
`) }] };
|
|
49739
|
+
});
|
|
49740
|
+
}
|
|
49741
|
+
|
|
49558
49742
|
// src/tools/open-position.ts
|
|
49559
49743
|
function formatOpenPreview(req, res) {
|
|
49560
49744
|
const lines = [
|
|
@@ -49599,7 +49783,7 @@ No transaction built (provide owner wallet pubkey to build transaction)`);
|
|
|
49599
49783
|
}
|
|
49600
49784
|
function registerOpenPositionTool(server, client) {
|
|
49601
49785
|
server.registerTool("open_position", {
|
|
49602
|
-
description: "Build a transaction to open a new perpetual position
|
|
49786
|
+
description: "Build a transaction to open a new perpetual futures position. Returns a preview (entry price, fees, leverage, liquidation price) AND an unsigned transaction. " + "Show the preview to the user before signing. Supports MARKET and LIMIT orders with optional TP/SL. " + "IMPORTANT: Use at least $11 input_amount if setting take_profit or stop_loss — collateral after fees must exceed $10 for TP/SL to work on-chain.",
|
|
49603
49787
|
inputSchema: {
|
|
49604
49788
|
input_token_symbol: exports_external.string().max(16).describe('Token to pay with: "USDC", "SOL", etc.'),
|
|
49605
49789
|
output_token_symbol: exports_external.string().max(16).describe('Market to trade: "SOL", "BTC", "ETH", etc.'),
|
|
@@ -49681,7 +49865,7 @@ Transaction (base64, unsigned — sign with wallet):`);
|
|
|
49681
49865
|
}
|
|
49682
49866
|
function registerClosePositionTool(server, client) {
|
|
49683
49867
|
server.registerTool("close_position", {
|
|
49684
|
-
description: "Build a transaction to close (fully or partially) an existing
|
|
49868
|
+
description: "Build a transaction to close (fully or partially) an existing position. Returns preview with PnL, fees, and receive amount, plus unsigned transaction. " + "For full close: set input_usd to position size. For partial: use smaller amount. Requires position_key from get_positions.",
|
|
49685
49869
|
inputSchema: {
|
|
49686
49870
|
position_key: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Position account pubkey to close"),
|
|
49687
49871
|
input_usd: exports_external.string().max(32).describe('USD amount to close, e.g. "500.00" for full or "250.00" for partial'),
|
|
@@ -49815,7 +49999,7 @@ Transaction (base64, unsigned — sign with wallet):`);
|
|
|
49815
49999
|
}
|
|
49816
50000
|
function registerReversePositionTool(server, client) {
|
|
49817
50001
|
server.registerTool("reverse_position", {
|
|
49818
|
-
description: "Build a transaction to reverse a position (close current + open opposite direction). For example, close a LONG and open a SHORT with
|
|
50002
|
+
description: "Build a transaction to reverse a position (close current + open opposite direction). For example, close a LONG and open a SHORT with same collateral. " + "Returns combined preview and a single unsigned transaction. Requires position_key from get_positions.",
|
|
49819
50003
|
inputSchema: {
|
|
49820
50004
|
position_key: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Position account pubkey to reverse"),
|
|
49821
50005
|
owner: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Wallet pubkey"),
|
|
@@ -56872,7 +57056,7 @@ var $VersionedTransaction = VersionedTransaction;
|
|
|
56872
57056
|
import fs from "node:fs";
|
|
56873
57057
|
function registerSignAndSendTool(server) {
|
|
56874
57058
|
server.registerTool("sign_and_send", {
|
|
56875
|
-
description: "Sign and submit a base64
|
|
57059
|
+
description: "Sign and submit a base64 transaction to Solana mainnet using the local keypair. " + "Call ONLY after a transaction tool returns transactionBase64 AND the user has approved the preview. " + "IRREVERSIBLE — always confirm with user first. Call immediately — blockhashes expire in ~60 seconds. " + "Returns the confirmed signature and a Solscan link.",
|
|
56876
57060
|
inputSchema: {
|
|
56877
57061
|
transaction_base64: exports_external.string().max(1e4).describe("The base64-encoded unsigned transaction returned by a transaction tool")
|
|
56878
57062
|
}
|
|
@@ -56937,13 +57121,20 @@ Signature: ${signature2}` }],
|
|
|
56937
57121
|
const lines = [
|
|
56938
57122
|
"=== Transaction Confirmed ===",
|
|
56939
57123
|
`Signature: ${signature2}`,
|
|
56940
|
-
`Explorer: https://solscan.io/tx/${signature2}
|
|
57124
|
+
`Explorer: https://solscan.io/tx/${signature2}`,
|
|
57125
|
+
"",
|
|
57126
|
+
"Next: Call get_positions (with owner) to verify the position, or get_orders to check trigger orders."
|
|
56941
57127
|
];
|
|
56942
57128
|
return { content: [{ type: "text", text: lines.join(`
|
|
56943
57129
|
`) }] };
|
|
56944
57130
|
} catch (e) {
|
|
57131
|
+
const msg = sanitizeError(e);
|
|
57132
|
+
const isBlockhashExpired = msg.includes("Blockhash not found") || msg.includes("block height exceeded");
|
|
57133
|
+
const hint = isBlockhashExpired ? `
|
|
57134
|
+
|
|
57135
|
+
The blockhash has expired (~60 seconds). Re-call the original transaction tool to get a fresh transaction, then call sign_and_send immediately.` : "";
|
|
56945
57136
|
return {
|
|
56946
|
-
content: [{ type: "text", text: `Transaction send failed: ${
|
|
57137
|
+
content: [{ type: "text", text: `Transaction send failed: ${msg}${hint}` }],
|
|
56947
57138
|
isError: true
|
|
56948
57139
|
};
|
|
56949
57140
|
}
|
|
@@ -56953,7 +57144,7 @@ Signature: ${signature2}` }],
|
|
|
56953
57144
|
// src/tools/trigger-orders.ts
|
|
56954
57145
|
function registerTriggerOrderTools(server, client) {
|
|
56955
57146
|
server.registerTool("place_trigger_order", {
|
|
56956
|
-
description: "Place a take-profit (TP) or stop-loss (SL) trigger order on an existing position.
|
|
57147
|
+
description: "Place a take-profit (TP) or stop-loss (SL) trigger order on an existing position. Up to 5 per position. " + "Use preview_tp_sl first to calculate optimal trigger prices. Returns unsigned transaction.",
|
|
56957
57148
|
inputSchema: {
|
|
56958
57149
|
market_symbol: exports_external.string().max(16).describe('Market symbol, e.g. "SOL", "BTC", "ETH"'),
|
|
56959
57150
|
side: exports_external.enum(["LONG", "SHORT"]).describe("Position side"),
|
|
@@ -56984,12 +57175,14 @@ WARNING: ${res.err}`);
|
|
|
56984
57175
|
lines.push(`
|
|
56985
57176
|
Transaction (base64, unsigned — sign with wallet):`);
|
|
56986
57177
|
lines.push(res.transactionBase64);
|
|
57178
|
+
lines.push(`
|
|
57179
|
+
Next: After signing, call get_orders with owner to see the order ID for editing/canceling.`);
|
|
56987
57180
|
}
|
|
56988
57181
|
return { content: [{ type: "text", text: lines.join(`
|
|
56989
57182
|
`) }] };
|
|
56990
57183
|
});
|
|
56991
57184
|
server.registerTool("edit_trigger_order", {
|
|
56992
|
-
description: "Edit an existing
|
|
57185
|
+
description: "Edit an existing TP or SL trigger order. Change trigger price, size, or type. Requires order_id (0-7) from get_orders. Returns unsigned transaction.",
|
|
56993
57186
|
inputSchema: {
|
|
56994
57187
|
market_symbol: exports_external.string().max(16).describe('Market symbol, e.g. "SOL", "BTC", "ETH"'),
|
|
56995
57188
|
side: exports_external.enum(["LONG", "SHORT"]).describe("Position side"),
|
|
@@ -57027,7 +57220,7 @@ Transaction (base64, unsigned — sign with wallet):`);
|
|
|
57027
57220
|
`) }] };
|
|
57028
57221
|
});
|
|
57029
57222
|
server.registerTool("cancel_trigger_order", {
|
|
57030
|
-
description: "Cancel a single
|
|
57223
|
+
description: "Cancel a single TP or SL trigger order. Requires order_id (0-7) from get_orders. Returns unsigned transaction.",
|
|
57031
57224
|
inputSchema: {
|
|
57032
57225
|
market_symbol: exports_external.string().max(16).describe('Market symbol, e.g. "SOL", "BTC", "ETH"'),
|
|
57033
57226
|
side: exports_external.enum(["LONG", "SHORT"]).describe("Position side"),
|
|
@@ -57059,7 +57252,7 @@ Transaction (base64, unsigned — sign with wallet):`);
|
|
|
57059
57252
|
`) }] };
|
|
57060
57253
|
});
|
|
57061
57254
|
server.registerTool("cancel_all_trigger_orders", {
|
|
57062
|
-
description: "Cancel ALL
|
|
57255
|
+
description: "Cancel ALL TP and SL trigger orders for a market+side in one transaction. Returns unsigned transaction.",
|
|
57063
57256
|
inputSchema: {
|
|
57064
57257
|
market_symbol: exports_external.string().max(16).describe('Market symbol, e.g. "SOL", "BTC", "ETH"'),
|
|
57065
57258
|
side: exports_external.enum(["LONG", "SHORT"]).describe("Position side"),
|
|
@@ -57098,6 +57291,8 @@ function registerReadTools(server, client) {
|
|
|
57098
57291
|
registerPositionTools(server, client);
|
|
57099
57292
|
registerOrderTools(server, client);
|
|
57100
57293
|
registerPoolDataTools(server, client);
|
|
57294
|
+
registerAccountSummaryTool(server, client);
|
|
57295
|
+
registerTradingOverviewTool(server, client);
|
|
57101
57296
|
}
|
|
57102
57297
|
function registerTransactionTools(server, client) {
|
|
57103
57298
|
registerOpenPositionTool(server, client);
|
|
@@ -57181,7 +57376,7 @@ try {
|
|
|
57181
57376
|
const client = new FlashApiClient(config2);
|
|
57182
57377
|
const server = new McpServer({
|
|
57183
57378
|
name: "flash-trade",
|
|
57184
|
-
version: "0.
|
|
57379
|
+
version: "0.4.0"
|
|
57185
57380
|
}, {
|
|
57186
57381
|
capabilities: {
|
|
57187
57382
|
tools: {},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flash-trade-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
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",
|