flash-trade-mcp 0.2.0 → 0.2.2
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 +100 -16
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -49229,15 +49229,84 @@ function registerHealthTools(server, client) {
|
|
|
49229
49229
|
}
|
|
49230
49230
|
|
|
49231
49231
|
// src/tools/markets.ts
|
|
49232
|
+
var VIRTUAL_CUSTODY_MAP = {
|
|
49233
|
+
"6bthDsp8pcGBGKVKCKZjV5JfuSUNRo62RG4hQHj1u4CK": { symbol: "BNB", pool: "Crypto.1", maxLeverage: "60.00" },
|
|
49234
|
+
A8SKWb3pwbFUtxLQhnpUTfy7CkxBpWGvTLYyJyWHCMWv: { symbol: "PYTH", pool: "Governance.1", maxLeverage: "60.00" },
|
|
49235
|
+
"5JtPiHFmkb1nv1Qvs3sryLgXmjs8p5iQexAseC2Ljjzg": { symbol: "KMNO", pool: "Governance.1", maxLeverage: "60.00" },
|
|
49236
|
+
"9GeU2eX2B8nLCJr7FKhXeR73fM2ULBwUXZqHov9iipxz": { symbol: "MET", pool: "Governance.1", maxLeverage: "15.00" },
|
|
49237
|
+
"7WWSRZSgFmp7UDfD1KHWYJ2CqXVbpCdQ5cQfgBxjpFeL": { symbol: "EUR", pool: "Virtual.1", maxLeverage: "550.00" },
|
|
49238
|
+
Ah1Kd146CtAexGvbVNWRMQ8aXJTJDf4AopNLQZKGfYck: { symbol: "GBP", pool: "Virtual.1", maxLeverage: "550.00" },
|
|
49239
|
+
ERiMNq88WEByvDUKsPsvkJRnvsDrPPhbWedn59cDfvXY: { symbol: "USDJPY", pool: "Virtual.1", maxLeverage: "550.00" },
|
|
49240
|
+
"2zB3Uv3SoFGe17UiGjPGrwBRA7edH3YRwtHWQES7KkqP": { symbol: "USDCNH", pool: "Virtual.1", maxLeverage: "550.00" },
|
|
49241
|
+
"3j1xiP6GckKCzsTm6sni5iy6zrpZX5BWZGbKCq5buk4d": { symbol: "XAU", pool: "Virtual.1", maxLeverage: "120.00" },
|
|
49242
|
+
GMqeFJ8LG5BcrRtVgvfQuA7giBETcY76ikC8h5hPh59h: { symbol: "XAG", pool: "Virtual.1", maxLeverage: "130.00" },
|
|
49243
|
+
"5mggznCHoC98t2xXNYPVR8cqNhRhYdhV7qGWqMoY6YSJ": { symbol: "CRUDEOIL", pool: "Virtual.1", maxLeverage: "7.00" },
|
|
49244
|
+
A2C8A9QMEQ1XAWjLSe7zUNRXSjDqQA4cpYzLYGvDZS1u: { symbol: "AMZN", pool: "Equity.1", maxLeverage: "12.00" },
|
|
49245
|
+
CK6ByFWy3fMbymx55SGhWi4yEv4HebdtdbLMwfPTZDwK: { symbol: "AAPL", pool: "Equity.1", maxLeverage: "12.00" },
|
|
49246
|
+
GDudQbq15yQuhvZ2N63qiYdQBiMipooeArcUgcwizd5b: { symbol: "AMD", pool: "Equity.1", maxLeverage: "12.00" },
|
|
49247
|
+
HbwAAHzRwNqrZMD9WzMJBYGnKqUrDLcodD9rvaEkPYXK: { symbol: "NVDA", pool: "Equity.1", maxLeverage: "12.00" },
|
|
49248
|
+
RQNURQjDbq2Yah2udtFTNT7TjR15vsPV3oJNnwYher8: { symbol: "TSLA", pool: "Equity.1", maxLeverage: "12.00" },
|
|
49249
|
+
ArnD1faZVVkkewX4HUSoDuht46egAtVvhDTFMJn3DkFo: { symbol: "SAMO", pool: "Community.3", maxLeverage: "50.00" }
|
|
49250
|
+
};
|
|
49251
|
+
function buildCustodySymbolMap(poolData) {
|
|
49252
|
+
const map3 = new Map;
|
|
49253
|
+
for (const pool of poolData.pools) {
|
|
49254
|
+
for (const c of pool.custodyStats) {
|
|
49255
|
+
map3.set(c.custodyAccount, {
|
|
49256
|
+
symbol: c.symbol,
|
|
49257
|
+
maxLeverage: c.maxLeverage,
|
|
49258
|
+
pool: pool.poolName
|
|
49259
|
+
});
|
|
49260
|
+
}
|
|
49261
|
+
}
|
|
49262
|
+
for (const [pubkey, info] of Object.entries(VIRTUAL_CUSTODY_MAP)) {
|
|
49263
|
+
if (!map3.has(pubkey)) {
|
|
49264
|
+
map3.set(pubkey, info);
|
|
49265
|
+
}
|
|
49266
|
+
}
|
|
49267
|
+
return map3;
|
|
49268
|
+
}
|
|
49269
|
+
function formatMarketsSummary(markets, custodyInfo) {
|
|
49270
|
+
const lines = [
|
|
49271
|
+
`${markets.length} markets available:
|
|
49272
|
+
`,
|
|
49273
|
+
"Symbol | Side | Pool | Max Lev | Pubkey",
|
|
49274
|
+
"-----------|-------|----------------|---------|----------------------------------------------"
|
|
49275
|
+
];
|
|
49276
|
+
const enriched = markets.map((m) => {
|
|
49277
|
+
const info = custodyInfo.get(m.account.target_custody);
|
|
49278
|
+
return {
|
|
49279
|
+
symbol: info?.symbol ?? "UNKNOWN",
|
|
49280
|
+
pool: info?.pool ?? "?",
|
|
49281
|
+
maxLeverage: info?.maxLeverage ?? "?",
|
|
49282
|
+
side: m.account.side,
|
|
49283
|
+
pubkey: m.pubkey,
|
|
49284
|
+
open: m.account.permissions.allow_open_position
|
|
49285
|
+
};
|
|
49286
|
+
}).sort((a, b) => a.pool.localeCompare(b.pool) || a.symbol.localeCompare(b.symbol) || a.side.localeCompare(b.side));
|
|
49287
|
+
for (const m of enriched) {
|
|
49288
|
+
const status = m.open ? "" : " [CLOSED]";
|
|
49289
|
+
lines.push(`${m.symbol.padEnd(10)} | ${m.side.padEnd(5)} | ${m.pool.padEnd(14)} | ${m.maxLeverage.padEnd(7)} | ${m.pubkey}${status}`);
|
|
49290
|
+
}
|
|
49291
|
+
lines.push(`
|
|
49292
|
+
Use get_market with a pubkey for full details. Use get_prices for current oracle prices.`);
|
|
49293
|
+
return lines.join(`
|
|
49294
|
+
`);
|
|
49295
|
+
}
|
|
49232
49296
|
function registerMarketTools(server, client) {
|
|
49233
49297
|
server.registerTool("get_markets", {
|
|
49234
|
-
description: "List all available perpetual futures markets on Flash Trade. Returns
|
|
49298
|
+
description: "List all available perpetual futures markets on Flash Trade. Returns a compact summary table with symbol, side (Long/Short), pool, max leverage, and market pubkey. For full details on a specific market, use get_market with the pubkey."
|
|
49235
49299
|
}, async () => {
|
|
49236
|
-
const markets = await
|
|
49237
|
-
|
|
49300
|
+
const [markets, poolData] = await Promise.all([
|
|
49301
|
+
client.getMarkets(),
|
|
49302
|
+
client.getPoolData()
|
|
49303
|
+
]);
|
|
49304
|
+
const custodyInfo = buildCustodySymbolMap(poolData);
|
|
49305
|
+
const text = formatMarketsSummary(markets, custodyInfo);
|
|
49306
|
+
return { content: [{ type: "text", text }] };
|
|
49238
49307
|
});
|
|
49239
49308
|
server.registerTool("get_market", {
|
|
49240
|
-
description: "Get detailed information about a specific market by its on-chain account pubkey. Returns full market configuration including
|
|
49309
|
+
description: "Get detailed information about a specific market by its on-chain account pubkey. Returns full market configuration including permissions and collective position data.",
|
|
49241
49310
|
inputSchema: { pubkey: exports_external.string().describe("Solana pubkey of the market account") }
|
|
49242
49311
|
}, async ({ pubkey }) => {
|
|
49243
49312
|
const market = await client.getMarket(pubkey);
|
|
@@ -49470,7 +49539,7 @@ function registerOpenPositionTool(server, client) {
|
|
|
49470
49539
|
input_token_symbol: exports_external.string().describe('Token to pay with: "USDC", "SOL", etc.'),
|
|
49471
49540
|
output_token_symbol: exports_external.string().describe('Market to trade: "SOL", "BTC", "ETH", etc.'),
|
|
49472
49541
|
input_amount: exports_external.string().describe('Amount of input token, e.g. "100.0"'),
|
|
49473
|
-
leverage: exports_external.
|
|
49542
|
+
leverage: exports_external.string().describe('Leverage multiplier, e.g. "5.0"'),
|
|
49474
49543
|
trade_type: exports_external.enum(["LONG", "SHORT"]).describe("Trade direction"),
|
|
49475
49544
|
owner: exports_external.string().describe("Wallet pubkey (required to build the transaction)"),
|
|
49476
49545
|
order_type: exports_external.enum(["MARKET", "LIMIT"]).optional().describe("Default: MARKET"),
|
|
@@ -49485,7 +49554,7 @@ function registerOpenPositionTool(server, client) {
|
|
|
49485
49554
|
inputTokenSymbol: params.input_token_symbol,
|
|
49486
49555
|
outputTokenSymbol: params.output_token_symbol,
|
|
49487
49556
|
inputAmountUi: params.input_amount,
|
|
49488
|
-
leverage: params.leverage,
|
|
49557
|
+
leverage: parseFloat(params.leverage),
|
|
49489
49558
|
tradeType: params.trade_type,
|
|
49490
49559
|
owner: params.owner,
|
|
49491
49560
|
orderType: params.order_type,
|
|
@@ -56727,9 +56796,13 @@ var $VersionedTransaction = VersionedTransaction;
|
|
|
56727
56796
|
|
|
56728
56797
|
// src/tools/sign-and-send.ts
|
|
56729
56798
|
import fs from "node:fs";
|
|
56799
|
+
function sanitizeError(e) {
|
|
56800
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
56801
|
+
return msg.replace(/\[[\d,\s]{20,}\]/g, "[REDACTED]").replace(/[0-9a-fA-F]{40,}/g, "[REDACTED]").replace(/[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{40,}/g, "[REDACTED]");
|
|
56802
|
+
}
|
|
56730
56803
|
function registerSignAndSendTool(server) {
|
|
56731
56804
|
server.registerTool("sign_and_send", {
|
|
56732
|
-
description: "Sign and submit a base64-encoded unsigned Solana transaction using the locally configured keypair. " + "Call this AFTER a transaction tool (open_position, close_position, add_collateral, remove_collateral, reverse_position) " + "returns a transactionBase64 string AND the user has reviewed and approved the preview. " + "The keypair is read from KEYPAIR_PATH (default: ~/.config/solana/id.json). " + "Returns the confirmed transaction signature and a Solscan link. " + "IMPORTANT: Always show the transaction preview to the user and get their approval BEFORE calling this tool. " + "This tool signs with the local keypair and submits to Solana mainnet — the action is IRREVERSIBLE.",
|
|
56805
|
+
description: "Sign and submit a base64-encoded unsigned Solana transaction using the locally configured keypair. " + "Call this AFTER a transaction tool (open_position, close_position, add_collateral, remove_collateral, reverse_position) " + "returns a transactionBase64 string AND the user has reviewed and approved the preview. " + "The keypair is read from KEYPAIR_PATH (default: ~/.config/solana/id.json). " + "Returns the confirmed transaction signature and a Solscan link. " + "IMPORTANT: Always show the transaction preview to the user and get their approval BEFORE calling this tool. " + "This tool signs with the local keypair and submits to Solana mainnet — the action is IRREVERSIBLE. " + "NOTE: This tool never exposes private key material in its output.",
|
|
56733
56806
|
inputSchema: {
|
|
56734
56807
|
transaction_base64: exports_external.string().describe("The base64-encoded unsigned transaction returned by a transaction tool")
|
|
56735
56808
|
}
|
|
@@ -56738,12 +56811,26 @@ function registerSignAndSendTool(server) {
|
|
|
56738
56811
|
const keypairPath = process.env.KEYPAIR_PATH ?? `${process.env.HOME}/.config/solana/id.json`;
|
|
56739
56812
|
let keypair;
|
|
56740
56813
|
try {
|
|
56741
|
-
const
|
|
56814
|
+
const raw = fs.readFileSync(keypairPath, "utf-8");
|
|
56815
|
+
let keypairData;
|
|
56816
|
+
try {
|
|
56817
|
+
keypairData = JSON.parse(raw);
|
|
56818
|
+
} catch {
|
|
56819
|
+
return {
|
|
56820
|
+
content: [{ type: "text", text: `Keypair file at ${keypairPath} is not valid JSON.` }],
|
|
56821
|
+
isError: true
|
|
56822
|
+
};
|
|
56823
|
+
}
|
|
56824
|
+
if (!Array.isArray(keypairData) || keypairData.length !== 64) {
|
|
56825
|
+
return {
|
|
56826
|
+
content: [{ type: "text", text: `Keypair file at ${keypairPath} does not contain a valid 64-byte Solana keypair.` }],
|
|
56827
|
+
isError: true
|
|
56828
|
+
};
|
|
56829
|
+
}
|
|
56742
56830
|
keypair = $Keypair.fromSecretKey(Uint8Array.from(keypairData));
|
|
56743
56831
|
} catch (e) {
|
|
56744
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
56745
56832
|
return {
|
|
56746
|
-
content: [{ type: "text", text: `Failed to load keypair from ${keypairPath}: ${
|
|
56833
|
+
content: [{ type: "text", text: `Failed to load keypair from ${keypairPath}: ${sanitizeError(e)}` }],
|
|
56747
56834
|
isError: true
|
|
56748
56835
|
};
|
|
56749
56836
|
}
|
|
@@ -56752,9 +56839,8 @@ function registerSignAndSendTool(server) {
|
|
|
56752
56839
|
const txBytes = Buffer.from(params.transaction_base64, "base64");
|
|
56753
56840
|
tx = $VersionedTransaction.deserialize(txBytes);
|
|
56754
56841
|
} catch (e) {
|
|
56755
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
56756
56842
|
return {
|
|
56757
|
-
content: [{ type: "text", text: `Failed to decode transaction: ${
|
|
56843
|
+
content: [{ type: "text", text: `Failed to decode transaction: ${sanitizeError(e)}` }],
|
|
56758
56844
|
isError: true
|
|
56759
56845
|
};
|
|
56760
56846
|
}
|
|
@@ -56781,15 +56867,13 @@ Signature: ${signature2}` }],
|
|
|
56781
56867
|
const lines = [
|
|
56782
56868
|
"=== Transaction Confirmed ===",
|
|
56783
56869
|
`Signature: ${signature2}`,
|
|
56784
|
-
`Wallet: ${keypair.publicKey.toBase58()}`,
|
|
56785
56870
|
`Explorer: https://solscan.io/tx/${signature2}`
|
|
56786
56871
|
];
|
|
56787
56872
|
return { content: [{ type: "text", text: lines.join(`
|
|
56788
56873
|
`) }] };
|
|
56789
56874
|
} catch (e) {
|
|
56790
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
56791
56875
|
return {
|
|
56792
|
-
content: [{ type: "text", text: `Transaction send failed: ${
|
|
56876
|
+
content: [{ type: "text", text: `Transaction send failed: ${sanitizeError(e)}` }],
|
|
56793
56877
|
isError: true
|
|
56794
56878
|
};
|
|
56795
56879
|
}
|
|
@@ -56888,7 +56972,7 @@ try {
|
|
|
56888
56972
|
const client = new FlashApiClient(config2);
|
|
56889
56973
|
const server = new McpServer({
|
|
56890
56974
|
name: "flash-trade",
|
|
56891
|
-
version: "0.2.
|
|
56975
|
+
version: "0.2.2"
|
|
56892
56976
|
}, {
|
|
56893
56977
|
capabilities: {
|
|
56894
56978
|
tools: {},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flash-trade-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
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",
|