@definitive-fi/mcp 1.1.2 → 1.2.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/server.js +206 -97
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -76,16 +76,28 @@ function createClient(baseUrl, apiKey, apiSecret) {
|
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
78
|
if (!response.ok) {
|
|
79
|
+
const issues = validationIssues(response.status, json);
|
|
79
80
|
return {
|
|
80
81
|
error: true,
|
|
81
82
|
status_code: response.status,
|
|
82
|
-
message: typeof json === "object" && json !== null && "message" in json ? String(json.message) : response.statusText
|
|
83
|
+
message: typeof json === "object" && json !== null && "message" in json ? String(json.message) : response.statusText,
|
|
84
|
+
...issues && { details: issues }
|
|
83
85
|
};
|
|
84
86
|
}
|
|
85
87
|
return json;
|
|
86
88
|
}
|
|
87
89
|
};
|
|
88
90
|
}
|
|
91
|
+
function validationIssues(status, json) {
|
|
92
|
+
if (status !== 400 || typeof json !== "object" || json === null) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const error = "error" in json ? json.error : undefined;
|
|
96
|
+
if (typeof error !== "object" || error === null || !("issues" in error)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
return Array.isArray(error.issues) ? error.issues : undefined;
|
|
100
|
+
}
|
|
89
101
|
|
|
90
102
|
|
|
91
103
|
function resolvePortfolioRoute(keyType, suffix, portfolioId, defaultPortfolioId) {
|
|
@@ -103,33 +115,131 @@ function resolvePortfolioRoute(keyType, suffix, portfolioId, defaultPortfolioId)
|
|
|
103
115
|
import { z } from "zod";
|
|
104
116
|
var zUUID = z.string().uuid();
|
|
105
117
|
var portfolioIdParam = zUUID.optional().describe("Portfolio UUID (required for organization keys without a default)");
|
|
106
|
-
var
|
|
107
|
-
"arbitrum",
|
|
108
|
-
"avalanche",
|
|
109
|
-
"base",
|
|
110
|
-
"blast",
|
|
111
|
-
"bsc",
|
|
112
|
-
"ethereum",
|
|
113
|
-
"optimism",
|
|
114
|
-
"polygon",
|
|
115
|
-
"solana",
|
|
116
|
-
"hyperevm",
|
|
117
|
-
"plasma",
|
|
118
|
-
"monad",
|
|
119
|
-
"robinhood"
|
|
120
|
-
]);
|
|
118
|
+
var chainParam = (label) => z.string().min(1).describe(`${label}, lowercase (e.g. ethereum, base, arbitrum, solana)`);
|
|
121
119
|
var jsonResult = (result) => ({
|
|
122
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
120
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
121
|
+
...isErrorResult(result) && { isError: true }
|
|
123
122
|
});
|
|
123
|
+
var isErrorResult = (result) => typeof result === "object" && result !== null && ("error" in result) && result.error === true;
|
|
124
124
|
|
|
125
125
|
|
|
126
126
|
import { z as z2 } from "zod";
|
|
127
|
+
var perpsSymbolParam = z2.string().min(1).max(32).describe('Perps market symbol. Qualify with the subvenue when the base symbol is ambiguous, e.g. "native:BTC" (core exchange) — a bare symbol works only when exactly one market uses it');
|
|
128
|
+
var MIN_EPOCH_MS = 1600000000000;
|
|
129
|
+
var MAX_EPOCH_MS = 4102444800000;
|
|
130
|
+
var epochMsParam = () => z2.number().int().min(MIN_EPOCH_MS).max(MAX_EPOCH_MS);
|
|
131
|
+
var startTimeParam = epochMsParam().optional().describe("Range start in epoch milliseconds");
|
|
132
|
+
var decimalStringParam = z2.string().max(40).regex(/^\d+(\.\d+)?$/, "must be a non-negative decimal string").refine((value) => Number(value) > 0, "must be greater than zero");
|
|
133
|
+
function registerPerpsReadTools(server, client, keyType, defaultPortfolioId) {
|
|
134
|
+
const resolve = (suffix, portfolioId) => resolvePortfolioRoute(keyType, `perps/${suffix}`, portfolioId, defaultPortfolioId);
|
|
135
|
+
server.tool("perps_list_markets", "List all perps markets with live mark/mid/oracle prices, funding rate, open interest, and leverage caps. Use each row's marketId to address the market in other perps tools.", {
|
|
136
|
+
portfolio_id: portfolioIdParam
|
|
137
|
+
}, async ({ portfolio_id }) => {
|
|
138
|
+
const result = await client.request("GET", resolve("markets", portfolio_id));
|
|
139
|
+
return jsonResult(result);
|
|
140
|
+
});
|
|
141
|
+
server.tool("perps_get_orderbook", "Get the L2 orderbook snapshot for a perps market: bid/ask price levels with sizes and order counts.", {
|
|
142
|
+
symbol: perpsSymbolParam,
|
|
143
|
+
portfolio_id: portfolioIdParam
|
|
144
|
+
}, async ({ symbol, portfolio_id }) => {
|
|
145
|
+
const result = await client.request("GET", resolve(`markets/${symbol}/orderbook`, portfolio_id));
|
|
146
|
+
return jsonResult(result);
|
|
147
|
+
});
|
|
148
|
+
server.tool("perps_get_candles", "Get OHLCV candles for a perps market. Defaults to the last 24 hours when no range is given.", {
|
|
149
|
+
symbol: perpsSymbolParam,
|
|
150
|
+
interval: z2.enum(["1m", "5m", "15m", "1h", "4h", "1d"]).default("1h").describe("Candle interval"),
|
|
151
|
+
start_time: startTimeParam,
|
|
152
|
+
end_time: epochMsParam().optional().describe("Range end in epoch milliseconds"),
|
|
153
|
+
portfolio_id: portfolioIdParam
|
|
154
|
+
}, async ({ symbol, interval, start_time, end_time, portfolio_id }) => {
|
|
155
|
+
const end = end_time ?? Date.now();
|
|
156
|
+
const start = start_time ?? Math.max(MIN_EPOCH_MS, end - 24 * 60 * 60 * 1000);
|
|
157
|
+
if (start >= end) {
|
|
158
|
+
throw new Error("end_time must be greater than start_time");
|
|
159
|
+
}
|
|
160
|
+
const result = await client.request("GET", resolve(`markets/${symbol}/candles`, portfolio_id), {
|
|
161
|
+
interval,
|
|
162
|
+
startTime: String(start),
|
|
163
|
+
endTime: String(end)
|
|
164
|
+
});
|
|
165
|
+
return jsonResult(result);
|
|
166
|
+
});
|
|
167
|
+
server.tool("perps_get_quote", "Get a size-aware execution estimate for a perps market against the live orderbook (anonymous — does not account for positions or margin).", {
|
|
168
|
+
symbol: perpsSymbolParam,
|
|
169
|
+
side: z2.enum(["buy", "sell"]).describe("Order side"),
|
|
170
|
+
size: decimalStringParam.describe('Order size in the base asset, decimal string (e.g. "0.5")'),
|
|
171
|
+
portfolio_id: portfolioIdParam
|
|
172
|
+
}, async ({ symbol, side, size, portfolio_id }) => {
|
|
173
|
+
const result = await client.request("GET", resolve(`markets/${symbol}/quote`, portfolio_id), { side, size });
|
|
174
|
+
return jsonResult(result);
|
|
175
|
+
});
|
|
176
|
+
server.tool("perps_get_funding", "Get historical funding entries and the predicted next funding for a perps market.", {
|
|
177
|
+
symbol: perpsSymbolParam,
|
|
178
|
+
start_time: startTimeParam,
|
|
179
|
+
portfolio_id: portfolioIdParam
|
|
180
|
+
}, async ({ symbol, start_time, portfolio_id }) => {
|
|
181
|
+
const params = {};
|
|
182
|
+
if (start_time != null)
|
|
183
|
+
params.startTime = String(start_time);
|
|
184
|
+
const result = await client.request("GET", resolve(`markets/${symbol}/funding`, portfolio_id), params);
|
|
185
|
+
return jsonResult(result);
|
|
186
|
+
});
|
|
187
|
+
server.tool("perps_get_account", "Get the perps account state: equity, withdrawable balance, margin usage, and open positions with entry/mark/liquidation prices and PnL.", {
|
|
188
|
+
portfolio_id: portfolioIdParam
|
|
189
|
+
}, async ({ portfolio_id }) => {
|
|
190
|
+
const result = await client.request("GET", resolve("account", portfolio_id));
|
|
191
|
+
return jsonResult(result);
|
|
192
|
+
});
|
|
193
|
+
server.tool("perps_get_account_status", "Get perps onboarding status for the portfolio (NO_ACCOUNT → READY) and whether it can trade. Check this first if account tools return errors.", {
|
|
194
|
+
portfolio_id: portfolioIdParam
|
|
195
|
+
}, async ({ portfolio_id }) => {
|
|
196
|
+
const result = await client.request("GET", resolve("account/status", portfolio_id));
|
|
197
|
+
return jsonResult(result);
|
|
198
|
+
});
|
|
199
|
+
server.tool("perps_list_open_orders", "List perps orders currently resting on the venue, including trigger orders and position TP/SL.", {
|
|
200
|
+
portfolio_id: portfolioIdParam
|
|
201
|
+
}, async ({ portfolio_id }) => {
|
|
202
|
+
const result = await client.request("GET", resolve("orders/open", portfolio_id));
|
|
203
|
+
return jsonResult(result);
|
|
204
|
+
});
|
|
205
|
+
server.tool("perps_get_order_history", "List historical perps orders with their final status and average fill price.", {
|
|
206
|
+
portfolio_id: portfolioIdParam
|
|
207
|
+
}, async ({ portfolio_id }) => {
|
|
208
|
+
const result = await client.request("GET", resolve("orders/history", portfolio_id));
|
|
209
|
+
return jsonResult(result);
|
|
210
|
+
});
|
|
211
|
+
server.tool("perps_list_fills", "List perps trade fills with price, size, fee, closed PnL, and direction.", {
|
|
212
|
+
portfolio_id: portfolioIdParam
|
|
213
|
+
}, async ({ portfolio_id }) => {
|
|
214
|
+
const result = await client.request("GET", resolve("fills", portfolio_id));
|
|
215
|
+
return jsonResult(result);
|
|
216
|
+
});
|
|
217
|
+
server.tool("perps_list_funding_payments", "List funding payments paid (negative) or received (positive) on perps positions.", {
|
|
218
|
+
start_time: startTimeParam,
|
|
219
|
+
portfolio_id: portfolioIdParam
|
|
220
|
+
}, async ({ start_time, portfolio_id }) => {
|
|
221
|
+
const params = {};
|
|
222
|
+
if (start_time != null)
|
|
223
|
+
params.startTime = String(start_time);
|
|
224
|
+
const result = await client.request("GET", resolve("funding-payments", portfolio_id), params);
|
|
225
|
+
return jsonResult(result);
|
|
226
|
+
});
|
|
227
|
+
server.tool("perps_get_fees", "Get the portfolio's current perps taker/maker fee rates.", {
|
|
228
|
+
portfolio_id: portfolioIdParam
|
|
229
|
+
}, async ({ portfolio_id }) => {
|
|
230
|
+
const result = await client.request("GET", resolve("fees", portfolio_id));
|
|
231
|
+
return jsonResult(result);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
import { z as z3 } from "zod";
|
|
127
237
|
function registerReadTools(server, client, keyType, defaultPortfolioId) {
|
|
128
238
|
const resolve = (suffix, portfolioId) => resolvePortfolioRoute(keyType, suffix, portfolioId, defaultPortfolioId);
|
|
129
239
|
server.tool("list_positions", "List current token holdings in the portfolio with balances, USD values, and P&L.", {
|
|
130
|
-
limit:
|
|
131
|
-
cursor:
|
|
132
|
-
include_dust_balances:
|
|
240
|
+
limit: z3.number().min(1).max(100).default(20).describe("Max positions to return (1-100)"),
|
|
241
|
+
cursor: z3.string().optional().describe("Pagination cursor from previous response's nextCursor field"),
|
|
242
|
+
include_dust_balances: z3.boolean().default(false).describe("Include positions worth less than $1"),
|
|
133
243
|
portfolio_id: portfolioIdParam
|
|
134
244
|
}, async ({ limit, cursor, include_dust_balances, portfolio_id }) => {
|
|
135
245
|
const path = resolve("positions", portfolio_id);
|
|
@@ -149,17 +259,17 @@ function registerReadTools(server, client, keyType, defaultPortfolioId) {
|
|
|
149
259
|
return jsonResult(result);
|
|
150
260
|
});
|
|
151
261
|
server.tool("list_transfers", "List historical transfers (deposits, withdrawals, swaps, bridge transactions) for the portfolio.", {
|
|
152
|
-
limit:
|
|
153
|
-
cursor:
|
|
154
|
-
action_types:
|
|
262
|
+
limit: z3.number().min(1).max(100).default(20).describe("Max transfers to return (1-100)"),
|
|
263
|
+
cursor: z3.string().optional().describe("Pagination cursor from previous response's nextCursor field"),
|
|
264
|
+
action_types: z3.array(z3.enum([
|
|
155
265
|
"VAULT_ACTION_DEPOSIT",
|
|
156
266
|
"VAULT_ACTION_WITHDRAW",
|
|
157
267
|
"VAULT_ACTION_BRIDGE_SEND",
|
|
158
268
|
"VAULT_ACTION_BRIDGE_RECEIVE",
|
|
159
269
|
"VAULT_ACTION_SWAP"
|
|
160
270
|
])).optional().describe("Filter by transfer action types"),
|
|
161
|
-
start_timestamp:
|
|
162
|
-
end_timestamp:
|
|
271
|
+
start_timestamp: z3.string().datetime().optional().describe("Start of time range (ISO 8601 string, e.g. 2025-01-01T00:00:00Z)"),
|
|
272
|
+
end_timestamp: z3.string().datetime().optional().describe("End of time range (ISO 8601 string, e.g. 2025-01-01T00:00:00Z)"),
|
|
163
273
|
portfolio_id: portfolioIdParam
|
|
164
274
|
}, async ({
|
|
165
275
|
limit,
|
|
@@ -183,8 +293,8 @@ function registerReadTools(server, client, keyType, defaultPortfolioId) {
|
|
|
183
293
|
return jsonResult(result);
|
|
184
294
|
});
|
|
185
295
|
server.tool("get_deposit_address", "Get a deposit address for a specific blockchain. Creates a vault if one doesn't exist for that chain.", {
|
|
186
|
-
chain:
|
|
187
|
-
wallet_address:
|
|
296
|
+
chain: chainParam("Blockchain network name"),
|
|
297
|
+
wallet_address: z3.string().min(1).describe("User's wallet address on this chain — ask the user if not provided"),
|
|
188
298
|
portfolio_id: portfolioIdParam
|
|
189
299
|
}, async ({ chain, wallet_address, portfolio_id }) => {
|
|
190
300
|
const path = resolve(`address/${chain}`, portfolio_id);
|
|
@@ -193,9 +303,9 @@ function registerReadTools(server, client, keyType, defaultPortfolioId) {
|
|
|
193
303
|
return jsonResult(result);
|
|
194
304
|
});
|
|
195
305
|
server.tool("list_orders", "List trade orders with optional status filtering. Returns order details including fill status and pricing.", {
|
|
196
|
-
limit:
|
|
197
|
-
cursor:
|
|
198
|
-
status:
|
|
306
|
+
limit: z3.number().min(1).max(100).default(20).describe("Max orders to return (1-100)"),
|
|
307
|
+
cursor: z3.string().optional().describe("Pagination cursor from previous response's nextCursor field"),
|
|
308
|
+
status: z3.enum([
|
|
199
309
|
"ORDER_STATUS_PENDING",
|
|
200
310
|
"ORDER_STATUS_ACCEPTED",
|
|
201
311
|
"ORDER_STATUS_PARTIALLY_FILLED",
|
|
@@ -224,8 +334,8 @@ function registerReadTools(server, client, keyType, defaultPortfolioId) {
|
|
|
224
334
|
if (keyType !== "organization")
|
|
225
335
|
return;
|
|
226
336
|
server.tool("list_portfolios", "List all portfolios in the organization. Organization API keys only.", {
|
|
227
|
-
limit:
|
|
228
|
-
cursor:
|
|
337
|
+
limit: z3.number().min(1).max(100).default(10).describe("Max portfolios to return (1-100)"),
|
|
338
|
+
cursor: z3.string().optional().describe("Pagination cursor from previous response's nextCursor field")
|
|
229
339
|
}, async ({ limit, cursor }) => {
|
|
230
340
|
const params = { limit: String(limit) };
|
|
231
341
|
if (cursor)
|
|
@@ -235,8 +345,8 @@ function registerReadTools(server, client, keyType, defaultPortfolioId) {
|
|
|
235
345
|
});
|
|
236
346
|
server.tool("get_fees", "Get fee summary for a portfolio over a time period. Organization API keys only.", {
|
|
237
347
|
portfolio_id: zUUID.describe("Portfolio UUID to get fees for"),
|
|
238
|
-
start_timestamp:
|
|
239
|
-
end_timestamp:
|
|
348
|
+
start_timestamp: z3.string().datetime().optional().describe("Start of time range (ISO 8601 string, e.g. 2025-01-01T00:00:00Z)"),
|
|
349
|
+
end_timestamp: z3.string().datetime().optional().describe("End of time range (ISO 8601 string, e.g. 2025-01-01T00:00:00Z)")
|
|
240
350
|
}, async ({ portfolio_id, start_timestamp, end_timestamp }) => {
|
|
241
351
|
const params = {};
|
|
242
352
|
if (start_timestamp)
|
|
@@ -249,9 +359,9 @@ function registerReadTools(server, client, keyType, defaultPortfolioId) {
|
|
|
249
359
|
}
|
|
250
360
|
|
|
251
361
|
|
|
252
|
-
import { z as
|
|
253
|
-
var OrderSideEnum =
|
|
254
|
-
var OrderTypeEnum =
|
|
362
|
+
import { z as z4 } from "zod";
|
|
363
|
+
var OrderSideEnum = z4.enum(["buy", "sell"]);
|
|
364
|
+
var OrderTypeEnum = z4.enum([
|
|
255
365
|
"market",
|
|
256
366
|
"limit",
|
|
257
367
|
"twap",
|
|
@@ -263,20 +373,20 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
263
373
|
const resolve = (suffix, portfolioId) => resolvePortfolioRoute(keyType, suffix, portfolioId, defaultPortfolioId);
|
|
264
374
|
server.tool("get_trade_quote", "Get a price quote for a trade order. This is the DEFAULT tool for all trades — use this unless the user explicitly asks for a QuickTrade. Supports market, limit, TWAP, stop, stop-loss, and take-profit order types. This does not execute any trade. Use the returned quote ID with submit_trade to execute.", {
|
|
265
375
|
type: OrderTypeEnum.describe("Order type"),
|
|
266
|
-
chain:
|
|
267
|
-
target_asset:
|
|
268
|
-
contra_asset:
|
|
269
|
-
qty:
|
|
376
|
+
chain: chainParam("Blockchain network name"),
|
|
377
|
+
target_asset: z4.string().min(1).describe("Target asset contract address"),
|
|
378
|
+
contra_asset: z4.string().min(1).describe("Contra (quote) asset contract address"),
|
|
379
|
+
qty: z4.string().min(1).describe("Order quantity as a decimal string"),
|
|
270
380
|
order_side: OrderSideEnum.describe("Buy or sell"),
|
|
271
|
-
limit_price:
|
|
272
|
-
limit_is_notional:
|
|
273
|
-
trigger_price:
|
|
274
|
-
trigger_is_notional:
|
|
275
|
-
duration_seconds:
|
|
276
|
-
target_twap_buckets:
|
|
277
|
-
trigger_type:
|
|
278
|
-
slippage_tolerance:
|
|
279
|
-
max_price_impact:
|
|
381
|
+
limit_price: z4.string().optional().describe("Limit price (for limit orders)"),
|
|
382
|
+
limit_is_notional: z4.boolean().optional().describe("Whether limit price is in notional terms"),
|
|
383
|
+
trigger_price: z4.string().optional().describe("Trigger price (for stop/stop-loss/take-profit orders)"),
|
|
384
|
+
trigger_is_notional: z4.boolean().optional().describe("Whether trigger price is in notional terms"),
|
|
385
|
+
duration_seconds: z4.number().optional().describe("TWAP duration in seconds"),
|
|
386
|
+
target_twap_buckets: z4.number().optional().describe("Number of TWAP buckets"),
|
|
387
|
+
trigger_type: z4.enum(["upper", "lower"]).optional().describe("Trigger type for stop-buy orders only (upper or lower price bound)"),
|
|
388
|
+
slippage_tolerance: z4.string().optional().describe("Slippage tolerance as a decimal string (e.g. '0.01' for 1%)"),
|
|
389
|
+
max_price_impact: z4.string().optional().describe("Max price impact as a decimal string (e.g. '0.01' for 1%)"),
|
|
280
390
|
portfolio_id: portfolioIdParam
|
|
281
391
|
}, { readOnlyHint: true }, async ({
|
|
282
392
|
type,
|
|
@@ -331,10 +441,10 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
331
441
|
return jsonResult(result);
|
|
332
442
|
});
|
|
333
443
|
server.tool("get_quicktrade_quote", "Get a price quote for a QuickTrade market swap. Only use when the user explicitly requests a QuickTrade. This does not execute any trade. Review the quote before executing with the quicktrade tool.", {
|
|
334
|
-
target_asset:
|
|
335
|
-
contra_asset:
|
|
336
|
-
chain:
|
|
337
|
-
qty:
|
|
444
|
+
target_asset: z4.string().min(1).describe("Target asset contract address"),
|
|
445
|
+
contra_asset: z4.string().min(1).describe("Contra (quote) asset contract address"),
|
|
446
|
+
chain: chainParam("Blockchain network name"),
|
|
447
|
+
qty: z4.string().min(1).describe("Order quantity as a decimal string"),
|
|
338
448
|
order_side: OrderSideEnum.describe("Buy or sell"),
|
|
339
449
|
portfolio_id: portfolioIdParam
|
|
340
450
|
}, { readOnlyHint: true }, async ({
|
|
@@ -358,11 +468,11 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
358
468
|
return jsonResult(result);
|
|
359
469
|
});
|
|
360
470
|
server.tool("bridge_quote", "Get a quote for a cross-chain bridge transfer. This does not move any funds. Review the routes and select a route_id before executing with bridge_submit.", {
|
|
361
|
-
from_asset_address:
|
|
362
|
-
from_chain:
|
|
363
|
-
to_asset_address:
|
|
364
|
-
to_chain:
|
|
365
|
-
from_amount:
|
|
471
|
+
from_asset_address: z4.string().min(1).describe("Source asset contract address"),
|
|
472
|
+
from_chain: chainParam("Source blockchain network"),
|
|
473
|
+
to_asset_address: z4.string().min(1).describe("Destination asset contract address"),
|
|
474
|
+
to_chain: chainParam("Destination blockchain network"),
|
|
475
|
+
from_amount: z4.string().min(1).describe("Amount to bridge as a decimal string"),
|
|
366
476
|
portfolio_id: portfolioIdParam
|
|
367
477
|
}, { readOnlyHint: true }, async ({
|
|
368
478
|
from_asset_address,
|
|
@@ -408,20 +518,20 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
408
518
|
server.tool("submit_trade", "Submit a trade order using a quote from get_trade_quote. This is irreversible — all order types (market, limit, stop, TWAP) may execute immediately. Always show the user the quote details and get confirmation before calling this tool. Pass the same parameters you used for get_trade_quote plus the quote_id.", {
|
|
409
519
|
quote_id: zUUID.describe("Quote UUID from get_trade_quote response (found in quote.quote.id)"),
|
|
410
520
|
type: OrderTypeEnum.describe("Order type"),
|
|
411
|
-
chain:
|
|
412
|
-
target_asset:
|
|
413
|
-
contra_asset:
|
|
414
|
-
qty:
|
|
521
|
+
chain: chainParam("Blockchain network name"),
|
|
522
|
+
target_asset: z4.string().min(1).describe("Target asset contract address"),
|
|
523
|
+
contra_asset: z4.string().min(1).describe("Contra (quote) asset contract address"),
|
|
524
|
+
qty: z4.string().min(1).describe("Order quantity as a decimal string"),
|
|
415
525
|
order_side: OrderSideEnum.describe("Buy or sell"),
|
|
416
|
-
limit_price:
|
|
417
|
-
limit_is_notional:
|
|
418
|
-
trigger_price:
|
|
419
|
-
trigger_is_notional:
|
|
420
|
-
duration_seconds:
|
|
421
|
-
target_twap_buckets:
|
|
422
|
-
trigger_type:
|
|
423
|
-
slippage_tolerance:
|
|
424
|
-
max_price_impact:
|
|
526
|
+
limit_price: z4.string().optional().describe("Limit price (for limit orders)"),
|
|
527
|
+
limit_is_notional: z4.boolean().optional().describe("Whether limit price is in notional terms"),
|
|
528
|
+
trigger_price: z4.string().optional().describe("Trigger price (for stop/stop-loss/take-profit orders)"),
|
|
529
|
+
trigger_is_notional: z4.boolean().optional().describe("Whether trigger price is in notional terms"),
|
|
530
|
+
duration_seconds: z4.number().optional().describe("TWAP duration in seconds"),
|
|
531
|
+
target_twap_buckets: z4.number().optional().describe("Number of TWAP buckets"),
|
|
532
|
+
trigger_type: z4.enum(["upper", "lower"]).optional().describe("Trigger type for stop-buy orders only"),
|
|
533
|
+
slippage_tolerance: z4.string().optional().describe("Slippage tolerance as a decimal string (e.g. '0.01' for 1%)"),
|
|
534
|
+
max_price_impact: z4.string().optional().describe("Max price impact as a decimal string (e.g. '0.01' for 1%)"),
|
|
425
535
|
portfolio_id: portfolioIdParam
|
|
426
536
|
}, {
|
|
427
537
|
readOnlyHint: false,
|
|
@@ -482,14 +592,14 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
482
592
|
return jsonResult(result);
|
|
483
593
|
});
|
|
484
594
|
server.tool("quicktrade", "Execute a QuickTrade market swap immediately. Only use when the user explicitly requests a QuickTrade. This is irreversible — funds move on-chain once submitted. Call get_quicktrade_quote first and confirm details with the user before executing, unless the user requests to skip the quote step.", {
|
|
485
|
-
target_asset:
|
|
486
|
-
contra_asset:
|
|
487
|
-
chain:
|
|
488
|
-
qty:
|
|
595
|
+
target_asset: z4.string().min(1).describe("Target asset contract address"),
|
|
596
|
+
contra_asset: z4.string().min(1).describe("Contra (quote) asset contract address"),
|
|
597
|
+
chain: chainParam("Blockchain network name"),
|
|
598
|
+
qty: z4.string().min(1).describe("Order quantity as a decimal string"),
|
|
489
599
|
order_side: OrderSideEnum.describe("Buy or sell"),
|
|
490
|
-
slippage_tolerance:
|
|
491
|
-
display_asset_price:
|
|
492
|
-
seconds_to_expire:
|
|
600
|
+
slippage_tolerance: z4.string().optional().describe("Slippage tolerance as a decimal string (e.g. '0.01' for 1%)"),
|
|
601
|
+
display_asset_price: z4.string().optional().describe("Target asset notional price for display validation"),
|
|
602
|
+
seconds_to_expire: z4.number().int().positive().optional().describe("Order expiry time in seconds"),
|
|
493
603
|
portfolio_id: portfolioIdParam
|
|
494
604
|
}, {
|
|
495
605
|
readOnlyHint: false,
|
|
@@ -525,12 +635,12 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
525
635
|
return jsonResult(result);
|
|
526
636
|
});
|
|
527
637
|
server.tool("bridge_submit", "Execute a cross-chain bridge transfer. This is irreversible — funds are sent from the source chain to the destination chain. Always call bridge_quote first and confirm the details with the user before executing.", {
|
|
528
|
-
from_chain:
|
|
529
|
-
to_chain:
|
|
530
|
-
from_asset_address:
|
|
531
|
-
to_asset_address:
|
|
532
|
-
from_amount:
|
|
533
|
-
route_id:
|
|
638
|
+
from_chain: chainParam("Source blockchain network"),
|
|
639
|
+
to_chain: chainParam("Destination blockchain network"),
|
|
640
|
+
from_asset_address: z4.string().min(1).describe("Source asset contract address"),
|
|
641
|
+
to_asset_address: z4.string().min(1).describe("Destination asset contract address"),
|
|
642
|
+
from_amount: z4.string().min(1).describe("Amount to bridge as a decimal string"),
|
|
643
|
+
route_id: z4.string().min(1).describe("Route ID from bridge_quote response"),
|
|
534
644
|
portfolio_id: portfolioIdParam
|
|
535
645
|
}, {
|
|
536
646
|
readOnlyHint: false,
|
|
@@ -560,7 +670,7 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
560
670
|
if (keyType !== "organization")
|
|
561
671
|
return;
|
|
562
672
|
server.tool("create_portfolio", "Create a new portfolio in the organization. Organization API keys only.", {
|
|
563
|
-
portfolio_name:
|
|
673
|
+
portfolio_name: z4.string().min(1).describe("Name for the new portfolio")
|
|
564
674
|
}, {
|
|
565
675
|
readOnlyHint: false,
|
|
566
676
|
destructiveHint: false
|
|
@@ -571,22 +681,21 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
571
681
|
}
|
|
572
682
|
|
|
573
683
|
|
|
574
|
-
import { z as
|
|
575
|
-
var McpEnvSchema =
|
|
576
|
-
DEFINITIVE_API_KEY:
|
|
577
|
-
DEFINITIVE_API_SECRET:
|
|
578
|
-
DEFINITIVE_BASE_URL:
|
|
579
|
-
DEFINITIVE_API_KEY_TYPE:
|
|
580
|
-
DEFINITIVE_PORTFOLIO_ID:
|
|
684
|
+
import { z as z5 } from "zod";
|
|
685
|
+
var McpEnvSchema = z5.object({
|
|
686
|
+
DEFINITIVE_API_KEY: z5.string().startsWith("dpka_"),
|
|
687
|
+
DEFINITIVE_API_SECRET: z5.string().startsWith("dpks_"),
|
|
688
|
+
DEFINITIVE_BASE_URL: z5.string().url().default("https://ddp.definitive.fi"),
|
|
689
|
+
DEFINITIVE_API_KEY_TYPE: z5.enum(["portfolio", "organization"]),
|
|
690
|
+
DEFINITIVE_PORTFOLIO_ID: z5.string().optional()
|
|
581
691
|
});
|
|
582
692
|
var env = McpEnvSchema.parse(process.env);
|
|
583
693
|
var client = createClient(env.DEFINITIVE_BASE_URL, env.DEFINITIVE_API_KEY, env.DEFINITIVE_API_SECRET);
|
|
584
|
-
var server = new McpServer({
|
|
585
|
-
|
|
586
|
-
version: "1.1.2",
|
|
587
|
-
instructions: "MCP server for the Definitive on-chain trading platform. Provides unified tools for portfolio management, trading (market/limit/TWAP/stop orders), QuickTrade execution across multiple blockchains. Tools auto-route to the correct API based on the configured key type (portfolio or organization). For organization keys, pass portfolio_id to target a specific portfolio, or set DEFINITIVE_PORTFOLIO_ID as default. TRADING: Default to get_trade_quote + submit_trade for trades unless the user specifies QuickTrade."
|
|
694
|
+
var server = new McpServer({ name: "Definitive", version: "1.2.1" }, {
|
|
695
|
+
instructions: "MCP server for the Definitive on-chain trading platform. Provides unified tools for portfolio management, trading (market/limit/TWAP/stop orders), QuickTrade execution across multiple blockchains, and read-only perps (perpetual futures) market data and account state. Tools auto-route to the correct API based on the configured key type (portfolio or organization). For organization keys, pass portfolio_id to target a specific portfolio, or set DEFINITIVE_PORTFOLIO_ID as default. TRADING: Default to get_trade_quote + submit_trade for trades unless the user specifies QuickTrade."
|
|
588
696
|
});
|
|
589
697
|
registerReadTools(server, client, env.DEFINITIVE_API_KEY_TYPE, env.DEFINITIVE_PORTFOLIO_ID);
|
|
590
698
|
registerWriteTools(server, client, env.DEFINITIVE_API_KEY_TYPE, env.DEFINITIVE_PORTFOLIO_ID);
|
|
699
|
+
registerPerpsReadTools(server, client, env.DEFINITIVE_API_KEY_TYPE, env.DEFINITIVE_PORTFOLIO_ID);
|
|
591
700
|
var transport = new StdioServerTransport;
|
|
592
701
|
await server.connect(transport);
|