flash-trade-mcp 0.3.0 → 0.3.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 +298 -84
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21063,7 +21063,7 @@ var require_fallback = __commonJS((exports, module) => {
|
|
|
21063
21063
|
|
|
21064
21064
|
// node_modules/bufferutil/index.js
|
|
21065
21065
|
var require_bufferutil = __commonJS((exports, module) => {
|
|
21066
|
-
var __dirname = "/
|
|
21066
|
+
var __dirname = "/home/runner/work/flash-trade-MCP/flash-trade-MCP/mcp/node_modules/bufferutil";
|
|
21067
21067
|
try {
|
|
21068
21068
|
module.exports = require_node_gyp_build2()(__dirname);
|
|
21069
21069
|
} catch (e) {
|
|
@@ -21479,7 +21479,7 @@ var require_fallback2 = __commonJS((exports, module) => {
|
|
|
21479
21479
|
|
|
21480
21480
|
// node_modules/utf-8-validate/index.js
|
|
21481
21481
|
var require_utf_8_validate = __commonJS((exports, module) => {
|
|
21482
|
-
var __dirname = "/
|
|
21482
|
+
var __dirname = "/home/runner/work/flash-trade-MCP/flash-trade-MCP/mcp/node_modules/utf-8-validate";
|
|
21483
21483
|
try {
|
|
21484
21484
|
module.exports = require_node_gyp_build2()(__dirname);
|
|
21485
21485
|
} catch (e) {
|
|
@@ -49053,6 +49053,15 @@ function loadConfig() {
|
|
|
49053
49053
|
if (!apiBaseUrl) {
|
|
49054
49054
|
throw new Error("FLASH_API_URL environment variable is required");
|
|
49055
49055
|
}
|
|
49056
|
+
let parsed;
|
|
49057
|
+
try {
|
|
49058
|
+
parsed = new URL(apiBaseUrl);
|
|
49059
|
+
} catch {
|
|
49060
|
+
throw new Error(`FLASH_API_URL is not a valid URL: ${apiBaseUrl}`);
|
|
49061
|
+
}
|
|
49062
|
+
if (parsed.protocol !== "https:") {
|
|
49063
|
+
console.error(`[flash-trade-mcp] WARNING: FLASH_API_URL uses ${parsed.protocol} — HTTPS is strongly recommended for production`);
|
|
49064
|
+
}
|
|
49056
49065
|
return {
|
|
49057
49066
|
apiBaseUrl: apiBaseUrl.replace(/\/$/, ""),
|
|
49058
49067
|
timeoutMs: parseInt(process.env.FLASH_API_TIMEOUT ?? "30000", 10),
|
|
@@ -49069,8 +49078,8 @@ class FlashApiError extends Error {
|
|
|
49069
49078
|
super(`Flash API error [${statusCode}] ${endpoint}: ${message}`);
|
|
49070
49079
|
this.statusCode = statusCode;
|
|
49071
49080
|
this.endpoint = endpoint;
|
|
49072
|
-
this.responseBody = responseBody;
|
|
49073
49081
|
this.name = "FlashApiError";
|
|
49082
|
+
this.responseBody = responseBody?.slice(0, 500);
|
|
49074
49083
|
}
|
|
49075
49084
|
}
|
|
49076
49085
|
|
|
@@ -49137,51 +49146,51 @@ class FlashApiClient {
|
|
|
49137
49146
|
return this.get("/markets");
|
|
49138
49147
|
}
|
|
49139
49148
|
async getMarket(pubkey) {
|
|
49140
|
-
return this.get(`/markets/${pubkey}`);
|
|
49149
|
+
return this.get(`/markets/${encodeURIComponent(pubkey)}`);
|
|
49141
49150
|
}
|
|
49142
49151
|
async getPools() {
|
|
49143
49152
|
return this.get("/pools");
|
|
49144
49153
|
}
|
|
49145
49154
|
async getPool(pubkey) {
|
|
49146
|
-
return this.get(`/pools/${pubkey}`);
|
|
49155
|
+
return this.get(`/pools/${encodeURIComponent(pubkey)}`);
|
|
49147
49156
|
}
|
|
49148
49157
|
async getCustodies() {
|
|
49149
49158
|
return this.get("/custodies");
|
|
49150
49159
|
}
|
|
49151
49160
|
async getCustody(pubkey) {
|
|
49152
|
-
return this.get(`/custodies/${pubkey}`);
|
|
49161
|
+
return this.get(`/custodies/${encodeURIComponent(pubkey)}`);
|
|
49153
49162
|
}
|
|
49154
49163
|
async getPrices() {
|
|
49155
49164
|
return this.get("/prices");
|
|
49156
49165
|
}
|
|
49157
49166
|
async getPrice(symbol2) {
|
|
49158
|
-
return this.get(`/prices/${symbol2}`);
|
|
49167
|
+
return this.get(`/prices/${encodeURIComponent(symbol2)}`);
|
|
49159
49168
|
}
|
|
49160
49169
|
async getPositions(owner) {
|
|
49161
|
-
const query = owner ? `?owner=${owner}` : "";
|
|
49170
|
+
const query = owner ? `?owner=${encodeURIComponent(owner)}` : "";
|
|
49162
49171
|
return this.get(`/positions${query}`);
|
|
49163
49172
|
}
|
|
49164
49173
|
async getPosition(pubkey) {
|
|
49165
|
-
return this.get(`/positions/${pubkey}`);
|
|
49174
|
+
return this.get(`/positions/${encodeURIComponent(pubkey)}`);
|
|
49166
49175
|
}
|
|
49167
49176
|
async getOwnerPositions(owner, includePnlInLeverage = false) {
|
|
49168
|
-
return this.get(`/positions/owner/${owner}?includePnlInLeverageDisplay=${includePnlInLeverage}`);
|
|
49177
|
+
return this.get(`/positions/owner/${encodeURIComponent(owner)}?includePnlInLeverageDisplay=${includePnlInLeverage}`);
|
|
49169
49178
|
}
|
|
49170
49179
|
async getOrders(owner) {
|
|
49171
|
-
const query = owner ? `?owner=${owner}` : "";
|
|
49180
|
+
const query = owner ? `?owner=${encodeURIComponent(owner)}` : "";
|
|
49172
49181
|
return this.get(`/orders${query}`);
|
|
49173
49182
|
}
|
|
49174
49183
|
async getOrder(pubkey) {
|
|
49175
|
-
return this.get(`/orders/${pubkey}`);
|
|
49184
|
+
return this.get(`/orders/${encodeURIComponent(pubkey)}`);
|
|
49176
49185
|
}
|
|
49177
49186
|
async getOwnerOrders(owner) {
|
|
49178
|
-
return this.get(`/orders/owner/${owner}`);
|
|
49187
|
+
return this.get(`/orders/owner/${encodeURIComponent(owner)}`);
|
|
49179
49188
|
}
|
|
49180
49189
|
async getPoolData() {
|
|
49181
49190
|
return this.get("/pool-data");
|
|
49182
49191
|
}
|
|
49183
49192
|
async getPoolSnapshot(poolPubkey) {
|
|
49184
|
-
return this.get(`/pool-data/${poolPubkey}`);
|
|
49193
|
+
return this.get(`/pool-data/${encodeURIComponent(poolPubkey)}`);
|
|
49185
49194
|
}
|
|
49186
49195
|
async openPosition(req) {
|
|
49187
49196
|
return this.post("/transaction-builder/open-position", req);
|
|
@@ -49198,6 +49207,18 @@ class FlashApiClient {
|
|
|
49198
49207
|
async reversePosition(req) {
|
|
49199
49208
|
return this.post("/transaction-builder/reverse-position", req);
|
|
49200
49209
|
}
|
|
49210
|
+
async placeTriggerOrder(req) {
|
|
49211
|
+
return this.post("/transaction-builder/place-trigger-order", req);
|
|
49212
|
+
}
|
|
49213
|
+
async editTriggerOrder(req) {
|
|
49214
|
+
return this.post("/transaction-builder/edit-trigger-order", req);
|
|
49215
|
+
}
|
|
49216
|
+
async cancelTriggerOrder(req) {
|
|
49217
|
+
return this.post("/transaction-builder/cancel-trigger-order", req);
|
|
49218
|
+
}
|
|
49219
|
+
async cancelAllTriggerOrders(req) {
|
|
49220
|
+
return this.post("/transaction-builder/cancel-all-trigger-orders", req);
|
|
49221
|
+
}
|
|
49201
49222
|
async previewLimitOrderFees(req) {
|
|
49202
49223
|
return this.post("/preview/limit-order-fees", req);
|
|
49203
49224
|
}
|
|
@@ -49220,8 +49241,9 @@ function registerHealthTools(server, client) {
|
|
|
49220
49241
|
const health = await client.getHealth();
|
|
49221
49242
|
const lines = [`Status: ${health.status}`];
|
|
49222
49243
|
for (const [key, val] of Object.entries(health)) {
|
|
49223
|
-
if (key !== "status")
|
|
49224
|
-
lines.push(`${key}: ${val}`);
|
|
49244
|
+
if (key !== "status") {
|
|
49245
|
+
lines.push(`${key}: ${typeof val === "object" ? JSON.stringify(val) : val}`);
|
|
49246
|
+
}
|
|
49225
49247
|
}
|
|
49226
49248
|
return { content: [{ type: "text", text: lines.join(`
|
|
49227
49249
|
`) }] };
|
|
@@ -49307,7 +49329,7 @@ function registerMarketTools(server, client) {
|
|
|
49307
49329
|
});
|
|
49308
49330
|
server.registerTool("get_market", {
|
|
49309
49331
|
description: "Get detailed information about a specific market by its on-chain account pubkey. Returns full market configuration including permissions and collective position data.",
|
|
49310
|
-
inputSchema: { pubkey: exports_external.string().describe("Solana pubkey of the market account") }
|
|
49332
|
+
inputSchema: { pubkey: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Solana pubkey of the market account") }
|
|
49311
49333
|
}, async ({ pubkey }) => {
|
|
49312
49334
|
const market = await client.getMarket(pubkey);
|
|
49313
49335
|
return { content: [{ type: "text", text: JSON.stringify(market, null, 2) }] };
|
|
@@ -49320,11 +49342,25 @@ function registerPoolTools(server, client) {
|
|
|
49320
49342
|
description: "List all liquidity pools on Flash Trade. Pools hold the collateral that backs perpetual positions. Returns pool addresses and configuration."
|
|
49321
49343
|
}, async () => {
|
|
49322
49344
|
const pools = await client.getPools();
|
|
49323
|
-
|
|
49345
|
+
const lines = [
|
|
49346
|
+
`${pools.length} pools available:
|
|
49347
|
+
`,
|
|
49348
|
+
"Pool Name | Custodies | Pubkey",
|
|
49349
|
+
"---------------|-----------|----------------------------------------------"
|
|
49350
|
+
];
|
|
49351
|
+
for (const p of pools) {
|
|
49352
|
+
const name = (p.account?.name ?? "Unknown").padEnd(15);
|
|
49353
|
+
const custodyCount = String(p.account?.custodies?.length ?? 0).padEnd(10);
|
|
49354
|
+
lines.push(`${name}| ${custodyCount}| ${p.pubkey}`);
|
|
49355
|
+
}
|
|
49356
|
+
lines.push(`
|
|
49357
|
+
Use get_pool with a pubkey for full details. Use get_pool_data for AUM and utilization metrics.`);
|
|
49358
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
49359
|
+
`) }] };
|
|
49324
49360
|
});
|
|
49325
49361
|
server.registerTool("get_pool", {
|
|
49326
49362
|
description: "Get detailed information about a specific pool by its on-chain account pubkey.",
|
|
49327
|
-
inputSchema: { pubkey: exports_external.string().describe("Solana pubkey of the pool account") }
|
|
49363
|
+
inputSchema: { pubkey: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Solana pubkey of the pool account") }
|
|
49328
49364
|
}, async ({ pubkey }) => {
|
|
49329
49365
|
const pool = await client.getPool(pubkey);
|
|
49330
49366
|
return { content: [{ type: "text", text: JSON.stringify(pool, null, 2) }] };
|
|
@@ -49341,7 +49377,7 @@ function registerCustodyTools(server, client) {
|
|
|
49341
49377
|
});
|
|
49342
49378
|
server.registerTool("get_custody", {
|
|
49343
49379
|
description: "Get detailed custody information for a specific custody account. Includes utilization, fees, and limits.",
|
|
49344
|
-
inputSchema: { pubkey: exports_external.string().describe("Solana pubkey of the custody account") }
|
|
49380
|
+
inputSchema: { pubkey: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Solana pubkey of the custody account") }
|
|
49345
49381
|
}, async ({ pubkey }) => {
|
|
49346
49382
|
const custody = await client.getCustody(pubkey);
|
|
49347
49383
|
return { content: [{ type: "text", text: JSON.stringify(custody, null, 2) }] };
|
|
@@ -49366,18 +49402,18 @@ function registerPriceTools(server, client) {
|
|
|
49366
49402
|
});
|
|
49367
49403
|
server.registerTool("get_price", {
|
|
49368
49404
|
description: 'Get the current oracle price for a specific asset symbol (e.g., "SOL", "BTC", "ETH"). Case-insensitive. Returns price in USD with timestamp.',
|
|
49369
|
-
inputSchema: { symbol: exports_external.string().describe('Asset symbol, e.g. "SOL", "BTC", "ETH"') }
|
|
49405
|
+
inputSchema: { symbol: exports_external.string().max(16).describe('Asset symbol, e.g. "SOL", "BTC", "ETH"') }
|
|
49370
49406
|
}, async ({ symbol: symbol2 }) => {
|
|
49371
49407
|
const data = await client.getPrice(symbol2);
|
|
49372
49408
|
const usd = formatPrice(data.price, data.exponent);
|
|
49373
|
-
|
|
49374
|
-
|
|
49375
|
-
|
|
49376
|
-
|
|
49377
|
-
|
|
49378
|
-
Timestamp: ${data.timestamp}`
|
|
49379
|
-
|
|
49380
|
-
|
|
49409
|
+
const lines = [
|
|
49410
|
+
`${symbol2.toUpperCase()}: $${usd}`,
|
|
49411
|
+
`Raw: ${data.price} (exp: ${data.exponent})`
|
|
49412
|
+
];
|
|
49413
|
+
if (data.timestamp)
|
|
49414
|
+
lines.push(`Timestamp: ${data.timestamp}`);
|
|
49415
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
49416
|
+
`) }] };
|
|
49381
49417
|
});
|
|
49382
49418
|
}
|
|
49383
49419
|
|
|
@@ -49400,7 +49436,7 @@ function registerPositionTools(server, client) {
|
|
|
49400
49436
|
server.registerTool("get_positions", {
|
|
49401
49437
|
description: "List perpetual positions, optionally filtered by wallet owner. Without an owner filter, returns ALL open positions (may be large). With owner, returns enriched positions with computed PnL, leverage, and liquidation price.",
|
|
49402
49438
|
inputSchema: {
|
|
49403
|
-
owner: exports_external.string().optional().describe("Wallet pubkey to filter by. When provided, returns enriched positions with PnL, leverage, and liquidation price.")
|
|
49439
|
+
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.")
|
|
49404
49440
|
}
|
|
49405
49441
|
}, async ({ owner }) => {
|
|
49406
49442
|
if (owner) {
|
|
@@ -49420,7 +49456,7 @@ ${text}` }] };
|
|
|
49420
49456
|
});
|
|
49421
49457
|
server.registerTool("get_position", {
|
|
49422
49458
|
description: "Get a single position by its on-chain account pubkey. Returns raw position data. For enriched data (PnL, leverage, liq price), use get_positions with the owner filter instead.",
|
|
49423
|
-
inputSchema: { pubkey: exports_external.string().describe("Position account pubkey") }
|
|
49459
|
+
inputSchema: { pubkey: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Position account pubkey") }
|
|
49424
49460
|
}, async ({ pubkey }) => {
|
|
49425
49461
|
const position = await client.getPosition(pubkey);
|
|
49426
49462
|
return { content: [{ type: "text", text: JSON.stringify(position, null, 2) }] };
|
|
@@ -49446,7 +49482,7 @@ function registerOrderTools(server, client) {
|
|
|
49446
49482
|
server.registerTool("get_orders", {
|
|
49447
49483
|
description: "List open orders (limit orders, take-profit, stop-loss), optionally filtered by wallet owner. When owner is provided, returns enriched order data with computed trigger prices and sizes.",
|
|
49448
49484
|
inputSchema: {
|
|
49449
|
-
owner: exports_external.string().optional().describe("Wallet pubkey to filter by. When provided, returns enriched orders.")
|
|
49485
|
+
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.")
|
|
49450
49486
|
}
|
|
49451
49487
|
}, async ({ owner }) => {
|
|
49452
49488
|
if (owner) {
|
|
@@ -49466,7 +49502,7 @@ ${text}` }] };
|
|
|
49466
49502
|
});
|
|
49467
49503
|
server.registerTool("get_order", {
|
|
49468
49504
|
description: "Get a single order account by its on-chain pubkey.",
|
|
49469
|
-
inputSchema: { pubkey: exports_external.string().describe("Order account pubkey") }
|
|
49505
|
+
inputSchema: { pubkey: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Order account pubkey") }
|
|
49470
49506
|
}, async ({ pubkey }) => {
|
|
49471
49507
|
const order = await client.getOrder(pubkey);
|
|
49472
49508
|
return { content: [{ type: "text", text: JSON.stringify(order, null, 2) }] };
|
|
@@ -49478,15 +49514,33 @@ function registerPoolDataTools(server, client) {
|
|
|
49478
49514
|
server.registerTool("get_pool_data", {
|
|
49479
49515
|
description: "Get computed pool metrics including AUM (assets under management), LP token stats, custody ratios, and utilization. Data is cached and refreshed every 15 seconds. Provide a pool_pubkey for a specific pool, or omit for all pools.",
|
|
49480
49516
|
inputSchema: {
|
|
49481
|
-
pool_pubkey: exports_external.string().optional().describe("Specific pool pubkey. If omitted, returns all pool snapshots.")
|
|
49517
|
+
pool_pubkey: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).optional().describe("Specific pool pubkey. If omitted, returns all pool snapshots.")
|
|
49482
49518
|
}
|
|
49483
49519
|
}, async ({ pool_pubkey }) => {
|
|
49484
49520
|
if (pool_pubkey) {
|
|
49485
49521
|
const snapshot = await client.getPoolSnapshot(pool_pubkey);
|
|
49486
49522
|
return { content: [{ type: "text", text: JSON.stringify(snapshot, null, 2) }] };
|
|
49487
49523
|
}
|
|
49488
|
-
const
|
|
49489
|
-
|
|
49524
|
+
const raw = await client.getPoolData();
|
|
49525
|
+
const pools = raw.pools ?? raw;
|
|
49526
|
+
const lines = [
|
|
49527
|
+
`${pools.length} pools:
|
|
49528
|
+
`,
|
|
49529
|
+
"Pool | AUM | LP Price | Stable% | Custodies",
|
|
49530
|
+
"---------------|--------------|----------|---------|----------"
|
|
49531
|
+
];
|
|
49532
|
+
for (const p of pools) {
|
|
49533
|
+
const name = (p.poolName ?? "Unknown").padEnd(15);
|
|
49534
|
+
const aum = `$${p.lpStats?.totalPoolValueUsd ?? "?"}`.padEnd(14);
|
|
49535
|
+
const lp = `$${p.lpStats?.lpPrice ?? "?"}`.padEnd(9);
|
|
49536
|
+
const stable = `${p.lpStats?.stableCoinPercentage ?? "?"}%`.padEnd(8);
|
|
49537
|
+
const custodies = (p.custodyStats ?? []).map((c) => c.symbol).join(", ");
|
|
49538
|
+
lines.push(`${name}| ${aum}| ${lp}| ${stable}| ${custodies}`);
|
|
49539
|
+
}
|
|
49540
|
+
lines.push(`
|
|
49541
|
+
Use get_pool_data with pool_pubkey for full custody stats.`);
|
|
49542
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
49543
|
+
`) }] };
|
|
49490
49544
|
});
|
|
49491
49545
|
}
|
|
49492
49546
|
|
|
@@ -49536,17 +49590,17 @@ function registerOpenPositionTool(server, client) {
|
|
|
49536
49590
|
server.registerTool("open_position", {
|
|
49537
49591
|
description: "Build a transaction to open a new perpetual position on Flash Trade. Returns a preview (entry price, fees, leverage, liquidation price) AND an unsigned transaction. The transaction must be signed by the user's wallet and submitted to Solana separately. IMPORTANT: Always present the preview to the user before they sign. This tool does NOT execute the trade. Supports both MARKET and LIMIT orders, with optional take-profit and stop-loss. COLLATERAL WARNING: Limit orders, take-profit, and stop-loss require >$10 collateral AFTER entry fees. A $10 position will have fees deducted, dropping collateral below $10 and preventing TP/SL/limit orders. Use at least $11-12 input_amount when planning to set TP/SL.",
|
|
49538
49592
|
inputSchema: {
|
|
49539
|
-
input_token_symbol: exports_external.string().describe('Token to pay with: "USDC", "SOL", etc.'),
|
|
49540
|
-
output_token_symbol: exports_external.string().describe('Market to trade: "SOL", "BTC", "ETH", etc.'),
|
|
49541
|
-
input_amount: exports_external.string().describe('Amount of input token, e.g. "100.0"'),
|
|
49542
|
-
leverage: exports_external.string().describe('Leverage multiplier, e.g. "5.0"'),
|
|
49593
|
+
input_token_symbol: exports_external.string().max(16).describe('Token to pay with: "USDC", "SOL", etc.'),
|
|
49594
|
+
output_token_symbol: exports_external.string().max(16).describe('Market to trade: "SOL", "BTC", "ETH", etc.'),
|
|
49595
|
+
input_amount: exports_external.string().max(32).describe('Amount of input token, e.g. "100.0"'),
|
|
49596
|
+
leverage: exports_external.string().max(8).describe('Leverage multiplier, e.g. "5.0"'),
|
|
49543
49597
|
trade_type: exports_external.enum(["LONG", "SHORT"]).describe("Trade direction"),
|
|
49544
|
-
owner: exports_external.string().describe("Wallet pubkey (required to build the transaction)"),
|
|
49598
|
+
owner: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Wallet pubkey (required to build the transaction)"),
|
|
49545
49599
|
order_type: exports_external.enum(["MARKET", "LIMIT"]).optional().describe("Default: MARKET"),
|
|
49546
|
-
limit_price: exports_external.string().optional().describe("Required for LIMIT orders, UI format price"),
|
|
49547
|
-
slippage_percentage: exports_external.string().optional().describe('Default: "0.5" (0.5%)'),
|
|
49548
|
-
take_profit: exports_external.string().optional().describe("TP trigger price in UI format"),
|
|
49549
|
-
stop_loss: exports_external.string().optional().describe("SL trigger price in UI format"),
|
|
49600
|
+
limit_price: exports_external.string().max(32).optional().describe("Required for LIMIT orders, UI format price"),
|
|
49601
|
+
slippage_percentage: exports_external.string().max(8).optional().describe('Default: "0.5" (0.5%)'),
|
|
49602
|
+
take_profit: exports_external.string().max(32).optional().describe("TP trigger price in UI format"),
|
|
49603
|
+
stop_loss: exports_external.string().max(32).optional().describe("SL trigger price in UI format"),
|
|
49550
49604
|
degen_mode: exports_external.boolean().optional().describe("Enable degen mode (higher leverage limits)")
|
|
49551
49605
|
}
|
|
49552
49606
|
}, async (params) => {
|
|
@@ -49564,12 +49618,21 @@ function registerOpenPositionTool(server, client) {
|
|
|
49564
49618
|
stopLoss: params.stop_loss,
|
|
49565
49619
|
degenMode: params.degen_mode
|
|
49566
49620
|
});
|
|
49567
|
-
|
|
49621
|
+
let text = formatOpenPreview({
|
|
49568
49622
|
outputTokenSymbol: params.output_token_symbol,
|
|
49569
49623
|
tradeType: params.trade_type,
|
|
49570
49624
|
inputTokenSymbol: params.input_token_symbol,
|
|
49571
49625
|
inputAmountUi: params.input_amount
|
|
49572
49626
|
}, res);
|
|
49627
|
+
if (params.take_profit || params.stop_loss) {
|
|
49628
|
+
const collateral = parseFloat(res.youPayUsdUi || "0");
|
|
49629
|
+
const fee = parseFloat(res.entryFee || "0");
|
|
49630
|
+
if (collateral - fee < 10) {
|
|
49631
|
+
text += `
|
|
49632
|
+
|
|
49633
|
+
WARNING: Collateral after fees is below $10. Take-profit and stop-loss orders require >$10 collateral and will FAIL on-chain. Use at least $11-12 input_amount.`;
|
|
49634
|
+
}
|
|
49635
|
+
}
|
|
49573
49636
|
return { content: [{ type: "text", text }] };
|
|
49574
49637
|
});
|
|
49575
49638
|
}
|
|
@@ -49609,11 +49672,11 @@ function registerClosePositionTool(server, client) {
|
|
|
49609
49672
|
server.registerTool("close_position", {
|
|
49610
49673
|
description: "Build a transaction to close (fully or partially) an existing perpetual position. Returns a preview with PnL, fees, and receive amount, plus an unsigned transaction. For a full close, set input_usd to the position's full size. For a partial close, use a smaller amount. The transaction must be signed and submitted separately.",
|
|
49611
49674
|
inputSchema: {
|
|
49612
|
-
position_key: exports_external.string().describe("Position account pubkey to close"),
|
|
49613
|
-
input_usd: exports_external.string().describe('USD amount to close, e.g. "500.00" for full or "250.00" for partial'),
|
|
49614
|
-
withdraw_token_symbol: exports_external.string().describe('Token to receive: "USDC", "SOL", etc.'),
|
|
49675
|
+
position_key: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Position account pubkey to close"),
|
|
49676
|
+
input_usd: exports_external.string().max(32).describe('USD amount to close, e.g. "500.00" for full or "250.00" for partial'),
|
|
49677
|
+
withdraw_token_symbol: exports_external.string().max(16).describe('Token to receive: "USDC", "SOL", etc.'),
|
|
49615
49678
|
keep_leverage_same: exports_external.boolean().optional().describe("Keep leverage constant during partial close"),
|
|
49616
|
-
slippage_percentage: exports_external.string().optional().describe('Default: "0.5" (0.5%)')
|
|
49679
|
+
slippage_percentage: exports_external.string().max(8).optional().describe('Default: "0.5" (0.5%)')
|
|
49617
49680
|
}
|
|
49618
49681
|
}, async (params) => {
|
|
49619
49682
|
const res = await client.closePosition({
|
|
@@ -49672,11 +49735,11 @@ function registerCollateralTools(server, client) {
|
|
|
49672
49735
|
server.registerTool("add_collateral", {
|
|
49673
49736
|
description: "Build a transaction to add collateral to an existing position. This reduces leverage and moves the liquidation price further from the current price (safer). Returns a preview and unsigned transaction.",
|
|
49674
49737
|
inputSchema: {
|
|
49675
|
-
position_key: exports_external.string().describe("Position account pubkey"),
|
|
49676
|
-
deposit_amount: exports_external.string().describe("Amount to deposit in UI format"),
|
|
49677
|
-
deposit_token_symbol: exports_external.string().describe('Token to deposit: "USDC", "SOL", etc.'),
|
|
49678
|
-
owner: exports_external.string().describe("Wallet pubkey"),
|
|
49679
|
-
slippage_percentage: exports_external.string().optional().describe('Default: "0.5" (0.5%)')
|
|
49738
|
+
position_key: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Position account pubkey"),
|
|
49739
|
+
deposit_amount: exports_external.string().max(32).describe("Amount to deposit in UI format"),
|
|
49740
|
+
deposit_token_symbol: exports_external.string().max(16).describe('Token to deposit: "USDC", "SOL", etc.'),
|
|
49741
|
+
owner: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Wallet pubkey"),
|
|
49742
|
+
slippage_percentage: exports_external.string().max(8).optional().describe('Default: "0.5" (0.5%)')
|
|
49680
49743
|
}
|
|
49681
49744
|
}, async (params) => {
|
|
49682
49745
|
const res = await client.addCollateral({
|
|
@@ -49691,11 +49754,11 @@ function registerCollateralTools(server, client) {
|
|
|
49691
49754
|
server.registerTool("remove_collateral", {
|
|
49692
49755
|
description: "Build a transaction to remove collateral from an existing position. This increases leverage and moves the liquidation price closer (riskier). WARNING: Removing too much collateral can lead to liquidation. Returns a preview and unsigned transaction.",
|
|
49693
49756
|
inputSchema: {
|
|
49694
|
-
position_key: exports_external.string().describe("Position account pubkey"),
|
|
49695
|
-
withdraw_amount_usd: exports_external.string().describe("USD amount to withdraw"),
|
|
49696
|
-
withdraw_token_symbol: exports_external.string().describe('Token to receive: "USDC", "SOL", etc.'),
|
|
49697
|
-
owner: exports_external.string().describe("Wallet pubkey"),
|
|
49698
|
-
slippage_percentage: exports_external.string().optional().describe('Default: "0.5" (0.5%)')
|
|
49757
|
+
position_key: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Position account pubkey"),
|
|
49758
|
+
withdraw_amount_usd: exports_external.string().max(32).describe("USD amount to withdraw"),
|
|
49759
|
+
withdraw_token_symbol: exports_external.string().max(16).describe('Token to receive: "USDC", "SOL", etc.'),
|
|
49760
|
+
owner: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Wallet pubkey"),
|
|
49761
|
+
slippage_percentage: exports_external.string().max(8).optional().describe('Default: "0.5" (0.5%)')
|
|
49699
49762
|
}
|
|
49700
49763
|
}, async (params) => {
|
|
49701
49764
|
const res = await client.removeCollateral({
|
|
@@ -49743,9 +49806,9 @@ function registerReversePositionTool(server, client) {
|
|
|
49743
49806
|
server.registerTool("reverse_position", {
|
|
49744
49807
|
description: "Build a transaction to reverse a position (close current + open opposite direction). For example, close a LONG and open a SHORT with the same collateral. Returns combined close+open preview and a single unsigned transaction.",
|
|
49745
49808
|
inputSchema: {
|
|
49746
|
-
position_key: exports_external.string().describe("Position account pubkey to reverse"),
|
|
49747
|
-
owner: exports_external.string().describe("Wallet pubkey"),
|
|
49748
|
-
slippage_percentage: exports_external.string().optional().describe('Default: "0.5" (0.5%)'),
|
|
49809
|
+
position_key: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Position account pubkey to reverse"),
|
|
49810
|
+
owner: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Wallet pubkey"),
|
|
49811
|
+
slippage_percentage: exports_external.string().max(8).optional().describe('Default: "0.5" (0.5%)'),
|
|
49749
49812
|
degen_mode: exports_external.boolean().optional().describe("Enable degen mode for the new position")
|
|
49750
49813
|
}
|
|
49751
49814
|
}, async (params) => {
|
|
@@ -49764,11 +49827,11 @@ function registerPreviewTools(server, client) {
|
|
|
49764
49827
|
server.registerTool("preview_limit_order_fees", {
|
|
49765
49828
|
description: "Preview the entry price, fees, liquidation price, and borrow rate for a limit order BEFORE placing it. Use this to evaluate a trade before committing. No transaction is built.",
|
|
49766
49829
|
inputSchema: {
|
|
49767
|
-
market_symbol: exports_external.string().describe('Market symbol, e.g. "SOL", "BTC", "ETH"'),
|
|
49768
|
-
input_amount: exports_external.string().describe("Collateral amount in UI format"),
|
|
49769
|
-
output_amount: exports_external.string().describe("Position size in target token"),
|
|
49830
|
+
market_symbol: exports_external.string().max(16).describe('Market symbol, e.g. "SOL", "BTC", "ETH"'),
|
|
49831
|
+
input_amount: exports_external.string().max(32).describe("Collateral amount in UI format"),
|
|
49832
|
+
output_amount: exports_external.string().max(32).describe("Position size in target token"),
|
|
49770
49833
|
side: exports_external.enum(["LONG", "SHORT"]).describe("Trade direction"),
|
|
49771
|
-
limit_price: exports_external.string().optional().describe("Limit price; uses live price if omitted"),
|
|
49834
|
+
limit_price: exports_external.string().max(32).optional().describe("Limit price; uses live price if omitted"),
|
|
49772
49835
|
trading_fee_discount_percent: exports_external.number().optional().describe("Fee discount from FAF staking (0-100)")
|
|
49773
49836
|
}
|
|
49774
49837
|
}, async (params) => {
|
|
@@ -49796,8 +49859,8 @@ WARNING: ${res.err}`);
|
|
|
49796
49859
|
server.registerTool("preview_exit_fee", {
|
|
49797
49860
|
description: "Preview the exit fee and exit price for closing a specific amount of a position. Use this to estimate close costs before calling close_position. No transaction is built.",
|
|
49798
49861
|
inputSchema: {
|
|
49799
|
-
position_key: exports_external.string().describe("Position account pubkey"),
|
|
49800
|
-
close_amount_usd: exports_external.string().describe("USD amount to close")
|
|
49862
|
+
position_key: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Position account pubkey"),
|
|
49863
|
+
close_amount_usd: exports_external.string().max(32).describe("USD amount to close")
|
|
49801
49864
|
}
|
|
49802
49865
|
}, async (params) => {
|
|
49803
49866
|
const res = await client.previewExitFee({
|
|
@@ -49819,14 +49882,14 @@ WARNING: ${res.err}`);
|
|
|
49819
49882
|
description: 'Calculate take-profit or stop-loss prices and projected PnL. Three modes: "forward" (trigger price → PnL), "reverse_pnl" (target PnL → trigger price), "reverse_roi" (target ROI% → trigger price). Works for existing positions (by pubkey) or hypothetical orders (provide market_symbol, entry_price, size, collateral, side).',
|
|
49820
49883
|
inputSchema: {
|
|
49821
49884
|
mode: exports_external.enum(["forward", "reverse_pnl", "reverse_roi"]).describe("Calculation mode"),
|
|
49822
|
-
position_key: exports_external.string().optional().describe("Position pubkey (for existing positions)"),
|
|
49823
|
-
market_symbol: exports_external.string().optional().describe("Market symbol (for hypothetical orders)"),
|
|
49824
|
-
entry_price: exports_external.string().optional().describe("Entry price (for hypothetical orders)"),
|
|
49825
|
-
size_usd: exports_external.string().optional().describe("Position size USD (for hypothetical orders)"),
|
|
49826
|
-
collateral_usd: exports_external.string().optional().describe("Collateral USD (for hypothetical orders)"),
|
|
49885
|
+
position_key: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).optional().describe("Position pubkey (for existing positions)"),
|
|
49886
|
+
market_symbol: exports_external.string().max(16).optional().describe("Market symbol (for hypothetical orders)"),
|
|
49887
|
+
entry_price: exports_external.string().max(32).optional().describe("Entry price (for hypothetical orders)"),
|
|
49888
|
+
size_usd: exports_external.string().max(32).optional().describe("Position size USD (for hypothetical orders)"),
|
|
49889
|
+
collateral_usd: exports_external.string().max(32).optional().describe("Collateral USD (for hypothetical orders)"),
|
|
49827
49890
|
side: exports_external.enum(["LONG", "SHORT"]).optional().describe("Side (for hypothetical orders)"),
|
|
49828
|
-
trigger_price: exports_external.string().optional().describe('Trigger price (required for "forward" mode)'),
|
|
49829
|
-
target_pnl_usd: exports_external.string().optional().describe('Target PnL USD (required for "reverse_pnl" mode)'),
|
|
49891
|
+
trigger_price: exports_external.string().max(32).optional().describe('Trigger price (required for "forward" mode)'),
|
|
49892
|
+
target_pnl_usd: exports_external.string().max(32).optional().describe('Target PnL USD (required for "reverse_pnl" mode)'),
|
|
49830
49893
|
target_roi_percent: exports_external.number().optional().describe('Target ROI% (required for "reverse_roi" mode)')
|
|
49831
49894
|
}
|
|
49832
49895
|
}, async (params) => {
|
|
@@ -49858,8 +49921,8 @@ WARNING: ${res.err}`);
|
|
|
49858
49921
|
server.registerTool("preview_margin", {
|
|
49859
49922
|
description: "Preview the effect of adding or removing margin (collateral) on a position. Shows new leverage, new liquidation price, and max adjustable amount. Use this before calling add_collateral or remove_collateral. No transaction is built.",
|
|
49860
49923
|
inputSchema: {
|
|
49861
|
-
position_key: exports_external.string().describe("Position account pubkey"),
|
|
49862
|
-
margin_delta_usd: exports_external.string().describe("Amount in USD to add or remove"),
|
|
49924
|
+
position_key: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Position account pubkey"),
|
|
49925
|
+
margin_delta_usd: exports_external.string().max(32).describe("Amount in USD to add or remove"),
|
|
49863
49926
|
action: exports_external.enum(["ADD", "REMOVE"]).describe("ADD to reduce leverage, REMOVE to increase leverage")
|
|
49864
49927
|
}
|
|
49865
49928
|
}, async (params) => {
|
|
@@ -56796,15 +56859,19 @@ var $VersionedTransaction = VersionedTransaction;
|
|
|
56796
56859
|
|
|
56797
56860
|
// src/tools/sign-and-send.ts
|
|
56798
56861
|
import fs from "node:fs";
|
|
56862
|
+
|
|
56863
|
+
// src/sanitize.ts
|
|
56799
56864
|
function sanitizeError(e) {
|
|
56800
56865
|
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]");
|
|
56866
|
+
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]");
|
|
56802
56867
|
}
|
|
56868
|
+
|
|
56869
|
+
// src/tools/sign-and-send.ts
|
|
56803
56870
|
function registerSignAndSendTool(server) {
|
|
56804
56871
|
server.registerTool("sign_and_send", {
|
|
56805
56872
|
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.",
|
|
56806
56873
|
inputSchema: {
|
|
56807
|
-
transaction_base64: exports_external.string().describe("The base64-encoded unsigned transaction returned by a transaction tool")
|
|
56874
|
+
transaction_base64: exports_external.string().max(1e4).describe("The base64-encoded unsigned transaction returned by a transaction tool")
|
|
56808
56875
|
}
|
|
56809
56876
|
}, async (params) => {
|
|
56810
56877
|
const rpcUrl = process.env.SOLANA_RPC_URL ?? "https://api.mainnet-beta.solana.com";
|
|
@@ -56880,6 +56947,152 @@ Signature: ${signature2}` }],
|
|
|
56880
56947
|
});
|
|
56881
56948
|
}
|
|
56882
56949
|
|
|
56950
|
+
// src/tools/trigger-orders.ts
|
|
56951
|
+
function registerTriggerOrderTools(server, client) {
|
|
56952
|
+
server.registerTool("place_trigger_order", {
|
|
56953
|
+
description: "Place a take-profit (TP) or stop-loss (SL) trigger order on an existing position. The trigger order will automatically close part or all of the position when the price hits the trigger level. Requires an open position for the given market/side. Returns an unsigned transaction. Up to 5 trigger orders per position.",
|
|
56954
|
+
inputSchema: {
|
|
56955
|
+
market_symbol: exports_external.string().max(16).describe('Market symbol, e.g. "SOL", "BTC", "ETH"'),
|
|
56956
|
+
collateral_symbol: exports_external.string().max(16).describe('Collateral token, e.g. "USDC", "JITOSOL"'),
|
|
56957
|
+
side: exports_external.enum(["LONG", "SHORT"]).describe("Position side"),
|
|
56958
|
+
trigger_price: exports_external.string().max(32).describe('Trigger price in UI format, e.g. "160.00"'),
|
|
56959
|
+
size_amount: exports_external.string().max(32).describe('Size in target token to close when triggered, e.g. "0.5"'),
|
|
56960
|
+
is_stop_loss: exports_external.boolean().describe("true = stop-loss, false = take-profit"),
|
|
56961
|
+
owner: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Wallet pubkey (must own the position)")
|
|
56962
|
+
}
|
|
56963
|
+
}, async (params) => {
|
|
56964
|
+
const res = await client.placeTriggerOrder({
|
|
56965
|
+
marketSymbol: params.market_symbol,
|
|
56966
|
+
collateralSymbol: params.collateral_symbol,
|
|
56967
|
+
side: params.side,
|
|
56968
|
+
triggerPriceUi: params.trigger_price,
|
|
56969
|
+
sizeAmountUi: params.size_amount,
|
|
56970
|
+
isStopLoss: params.is_stop_loss,
|
|
56971
|
+
owner: params.owner
|
|
56972
|
+
});
|
|
56973
|
+
const lines = [
|
|
56974
|
+
`=== Place ${params.is_stop_loss ? "Stop-Loss" : "Take-Profit"} Order ===`,
|
|
56975
|
+
`Market: ${params.market_symbol} ${params.side}`,
|
|
56976
|
+
`Trigger: $${params.trigger_price}`,
|
|
56977
|
+
`Size: ${params.size_amount} ${params.market_symbol}`
|
|
56978
|
+
];
|
|
56979
|
+
if (res.err)
|
|
56980
|
+
lines.push(`
|
|
56981
|
+
WARNING: ${res.err}`);
|
|
56982
|
+
if (res.transactionBase64) {
|
|
56983
|
+
lines.push(`
|
|
56984
|
+
Transaction (base64, unsigned — sign with wallet):`);
|
|
56985
|
+
lines.push(res.transactionBase64);
|
|
56986
|
+
}
|
|
56987
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
56988
|
+
`) }] };
|
|
56989
|
+
});
|
|
56990
|
+
server.registerTool("edit_trigger_order", {
|
|
56991
|
+
description: "Edit an existing take-profit or stop-loss trigger order. Change the trigger price, size, or order type without canceling and re-placing. Requires the order_id (0-7) from get_orders. Returns an unsigned transaction.",
|
|
56992
|
+
inputSchema: {
|
|
56993
|
+
market_symbol: exports_external.string().max(16).describe('Market symbol, e.g. "SOL", "BTC", "ETH"'),
|
|
56994
|
+
collateral_symbol: exports_external.string().max(16).describe('Collateral token, e.g. "USDC", "JITOSOL"'),
|
|
56995
|
+
side: exports_external.enum(["LONG", "SHORT"]).describe("Position side"),
|
|
56996
|
+
order_id: exports_external.number().describe("Index of the trigger order to edit (0-7)"),
|
|
56997
|
+
trigger_price: exports_external.string().max(32).describe("New trigger price in UI format"),
|
|
56998
|
+
size_amount: exports_external.string().max(32).describe("New size in target token"),
|
|
56999
|
+
is_stop_loss: exports_external.boolean().describe("true = stop-loss, false = take-profit"),
|
|
57000
|
+
owner: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Wallet pubkey (must be original order owner)")
|
|
57001
|
+
}
|
|
57002
|
+
}, async (params) => {
|
|
57003
|
+
const res = await client.editTriggerOrder({
|
|
57004
|
+
marketSymbol: params.market_symbol,
|
|
57005
|
+
collateralSymbol: params.collateral_symbol,
|
|
57006
|
+
side: params.side,
|
|
57007
|
+
orderId: params.order_id,
|
|
57008
|
+
triggerPriceUi: params.trigger_price,
|
|
57009
|
+
sizeAmountUi: params.size_amount,
|
|
57010
|
+
isStopLoss: params.is_stop_loss,
|
|
57011
|
+
owner: params.owner
|
|
57012
|
+
});
|
|
57013
|
+
const lines = [
|
|
57014
|
+
`=== Edit ${params.is_stop_loss ? "Stop-Loss" : "Take-Profit"} Order #${params.order_id} ===`,
|
|
57015
|
+
`Market: ${params.market_symbol} ${params.side}`,
|
|
57016
|
+
`New Trigger: $${params.trigger_price}`,
|
|
57017
|
+
`New Size: ${params.size_amount} ${params.market_symbol}`
|
|
57018
|
+
];
|
|
57019
|
+
if (res.err)
|
|
57020
|
+
lines.push(`
|
|
57021
|
+
WARNING: ${res.err}`);
|
|
57022
|
+
if (res.transactionBase64) {
|
|
57023
|
+
lines.push(`
|
|
57024
|
+
Transaction (base64, unsigned — sign with wallet):`);
|
|
57025
|
+
lines.push(res.transactionBase64);
|
|
57026
|
+
}
|
|
57027
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
57028
|
+
`) }] };
|
|
57029
|
+
});
|
|
57030
|
+
server.registerTool("cancel_trigger_order", {
|
|
57031
|
+
description: "Cancel a single take-profit or stop-loss trigger order. Requires the order_id (0-7) from get_orders. Returns an unsigned transaction.",
|
|
57032
|
+
inputSchema: {
|
|
57033
|
+
market_symbol: exports_external.string().max(16).describe('Market symbol, e.g. "SOL", "BTC", "ETH"'),
|
|
57034
|
+
collateral_symbol: exports_external.string().max(16).describe('Collateral token, e.g. "USDC", "JITOSOL"'),
|
|
57035
|
+
side: exports_external.enum(["LONG", "SHORT"]).describe("Position side"),
|
|
57036
|
+
order_id: exports_external.number().describe("Index of the trigger order to cancel (0-7)"),
|
|
57037
|
+
is_stop_loss: exports_external.boolean().describe("true = stop-loss, false = take-profit"),
|
|
57038
|
+
owner: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Wallet pubkey (must own the order)")
|
|
57039
|
+
}
|
|
57040
|
+
}, async (params) => {
|
|
57041
|
+
const res = await client.cancelTriggerOrder({
|
|
57042
|
+
marketSymbol: params.market_symbol,
|
|
57043
|
+
collateralSymbol: params.collateral_symbol,
|
|
57044
|
+
side: params.side,
|
|
57045
|
+
orderId: params.order_id,
|
|
57046
|
+
isStopLoss: params.is_stop_loss,
|
|
57047
|
+
owner: params.owner
|
|
57048
|
+
});
|
|
57049
|
+
const lines = [
|
|
57050
|
+
`=== Cancel ${params.is_stop_loss ? "Stop-Loss" : "Take-Profit"} Order #${params.order_id} ===`,
|
|
57051
|
+
`Market: ${params.market_symbol} ${params.side}`
|
|
57052
|
+
];
|
|
57053
|
+
if (res.err)
|
|
57054
|
+
lines.push(`
|
|
57055
|
+
WARNING: ${res.err}`);
|
|
57056
|
+
if (res.transactionBase64) {
|
|
57057
|
+
lines.push(`
|
|
57058
|
+
Transaction (base64, unsigned — sign with wallet):`);
|
|
57059
|
+
lines.push(res.transactionBase64);
|
|
57060
|
+
}
|
|
57061
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
57062
|
+
`) }] };
|
|
57063
|
+
});
|
|
57064
|
+
server.registerTool("cancel_all_trigger_orders", {
|
|
57065
|
+
description: "Cancel ALL take-profit and stop-loss trigger orders for a market+side. Removes all TP and SL orders in one transaction. Returns an unsigned transaction.",
|
|
57066
|
+
inputSchema: {
|
|
57067
|
+
market_symbol: exports_external.string().max(16).describe('Market symbol, e.g. "SOL", "BTC", "ETH"'),
|
|
57068
|
+
collateral_symbol: exports_external.string().max(16).describe('Collateral token, e.g. "USDC", "JITOSOL"'),
|
|
57069
|
+
side: exports_external.enum(["LONG", "SHORT"]).describe("Position side"),
|
|
57070
|
+
owner: exports_external.string().regex(/^[1-9A-HJ-NP-Za-km-z]{32,44}$/).describe("Wallet pubkey (must own the orders)")
|
|
57071
|
+
}
|
|
57072
|
+
}, async (params) => {
|
|
57073
|
+
const res = await client.cancelAllTriggerOrders({
|
|
57074
|
+
marketSymbol: params.market_symbol,
|
|
57075
|
+
collateralSymbol: params.collateral_symbol,
|
|
57076
|
+
side: params.side,
|
|
57077
|
+
owner: params.owner
|
|
57078
|
+
});
|
|
57079
|
+
const lines = [
|
|
57080
|
+
`=== Cancel All Trigger Orders ===`,
|
|
57081
|
+
`Market: ${params.market_symbol} ${params.side}`
|
|
57082
|
+
];
|
|
57083
|
+
if (res.err)
|
|
57084
|
+
lines.push(`
|
|
57085
|
+
WARNING: ${res.err}`);
|
|
57086
|
+
if (res.transactionBase64) {
|
|
57087
|
+
lines.push(`
|
|
57088
|
+
Transaction (base64, unsigned — sign with wallet):`);
|
|
57089
|
+
lines.push(res.transactionBase64);
|
|
57090
|
+
}
|
|
57091
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
57092
|
+
`) }] };
|
|
57093
|
+
});
|
|
57094
|
+
}
|
|
57095
|
+
|
|
56883
57096
|
// src/tools/index.ts
|
|
56884
57097
|
function registerReadTools(server, client) {
|
|
56885
57098
|
registerHealthTools(server, client);
|
|
@@ -56896,6 +57109,7 @@ function registerTransactionTools(server, client) {
|
|
|
56896
57109
|
registerClosePositionTool(server, client);
|
|
56897
57110
|
registerCollateralTools(server, client);
|
|
56898
57111
|
registerReversePositionTool(server, client);
|
|
57112
|
+
registerTriggerOrderTools(server, client);
|
|
56899
57113
|
registerSignAndSendTool(server);
|
|
56900
57114
|
}
|
|
56901
57115
|
|
|
@@ -56960,11 +57174,11 @@ function registerResources(server, client) {
|
|
|
56960
57174
|
|
|
56961
57175
|
// src/index.ts
|
|
56962
57176
|
process.on("uncaughtException", (err) => {
|
|
56963
|
-
console.error("[flash-trade-mcp] Uncaught exception:", err);
|
|
57177
|
+
console.error("[flash-trade-mcp] Uncaught exception:", sanitizeError(err));
|
|
56964
57178
|
process.exit(1);
|
|
56965
57179
|
});
|
|
56966
57180
|
process.on("unhandledRejection", (reason) => {
|
|
56967
|
-
console.error("[flash-trade-mcp] Unhandled rejection:", reason);
|
|
57181
|
+
console.error("[flash-trade-mcp] Unhandled rejection:", sanitizeError(reason));
|
|
56968
57182
|
process.exit(1);
|
|
56969
57183
|
});
|
|
56970
57184
|
try {
|
|
@@ -56972,7 +57186,7 @@ try {
|
|
|
56972
57186
|
const client = new FlashApiClient(config2);
|
|
56973
57187
|
const server = new McpServer({
|
|
56974
57188
|
name: "flash-trade",
|
|
56975
|
-
version: "0.
|
|
57189
|
+
version: "0.3.2"
|
|
56976
57190
|
}, {
|
|
56977
57191
|
capabilities: {
|
|
56978
57192
|
tools: {},
|
|
@@ -56986,6 +57200,6 @@ try {
|
|
|
56986
57200
|
const transport = new StdioServerTransport;
|
|
56987
57201
|
await server.connect(transport);
|
|
56988
57202
|
} catch (err) {
|
|
56989
|
-
console.error("[flash-trade-mcp] Fatal startup error:", err);
|
|
57203
|
+
console.error("[flash-trade-mcp] Fatal startup error:", sanitizeError(err));
|
|
56990
57204
|
process.exit(1);
|
|
56991
57205
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "flash-trade-mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.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",
|