@definitive-fi/mcp 1.2.1 → 1.3.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/README.md +1 -1
- package/dist/server.js +129 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,5 +33,5 @@ New to Definitive? Visit the [Definitive API documentation](https://ddp.definiti
|
|
|
33
33
|
| `DEFINITIVE_API_KEY` | Yes | Your Definitive API key |
|
|
34
34
|
| `DEFINITIVE_API_SECRET` | Yes | Your Definitive API secret |
|
|
35
35
|
| `DEFINITIVE_API_KEY_TYPE` | Yes | Key type: `"portfolio"` or `"organization"` |
|
|
36
|
-
| `DEFINITIVE_BASE_URL` | No | API base URL |
|
|
36
|
+
| `DEFINITIVE_BASE_URL` | No | API base URL. Must use `https`; defaults to `https://ddp.definitive.fi`. A different host prints a warning at startup |
|
|
37
37
|
| `DEFINITIVE_PORTFOLIO_ID` | No | Portfolio ID (required for organization keys when targeting a specific portfolio) |
|
package/dist/server.js
CHANGED
|
@@ -124,7 +124,7 @@ var isErrorResult = (result) => typeof result === "object" && result !== null &&
|
|
|
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');
|
|
127
|
+
var perpsSymbolParam = z2.string().min(1).max(32).regex(/^[A-Za-z0-9:._-]+$/, "must contain only letters, digits, and : . _ -").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
128
|
var MIN_EPOCH_MS = 1600000000000;
|
|
129
129
|
var MAX_EPOCH_MS = 4102444800000;
|
|
130
130
|
var epochMsParam = () => z2.number().int().min(MIN_EPOCH_MS).max(MAX_EPOCH_MS);
|
|
@@ -231,6 +231,125 @@ function registerPerpsReadTools(server, client, keyType, defaultPortfolioId) {
|
|
|
231
231
|
return jsonResult(result);
|
|
232
232
|
});
|
|
233
233
|
}
|
|
234
|
+
var evmAddressParam = z2.string().regex(/^0x[a-fA-F0-9]{40}$/, "must be a 0x-prefixed 20-byte hex address");
|
|
235
|
+
var hex32Param = z2.string().regex(/^0x[a-fA-F0-9]{64}$/, "must be a 0x-prefixed 32-byte hex string");
|
|
236
|
+
var depositFields = {
|
|
237
|
+
source_vault_id: zUUID.describe("Trading vault that sends the funds: vaults[].vaultId from get_portfolio"),
|
|
238
|
+
destination_portfolio_id: zUUID.describe("Portfolio whose perps account receives the funds; it must already have a perps account (see perps_get_account_status)"),
|
|
239
|
+
from_asset_address: z2.string().min(1).describe("Contract address of the asset to send, on the source vault's chain"),
|
|
240
|
+
from_amount: decimalStringParam.describe('Amount of the asset to send, decimal string (e.g. "250")'),
|
|
241
|
+
portfolio_id: portfolioIdParam
|
|
242
|
+
};
|
|
243
|
+
function registerPerpsWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
244
|
+
const resolve = (suffix, portfolioId) => resolvePortfolioRoute(keyType, `perps/${suffix}`, portfolioId, defaultPortfolioId);
|
|
245
|
+
server.tool("perps_preview_order", "Validate a proposed perps order against the live account and preview its cost, margin, and fees. Nothing is placed. Requires a WRITE-scoped key.", {
|
|
246
|
+
symbol: perpsSymbolParam,
|
|
247
|
+
side: z2.enum(["buy", "sell"]).describe("Order side"),
|
|
248
|
+
order_type: z2.enum([
|
|
249
|
+
"market",
|
|
250
|
+
"limit",
|
|
251
|
+
"stop_market",
|
|
252
|
+
"stop_limit",
|
|
253
|
+
"take_profit_market",
|
|
254
|
+
"take_profit_limit",
|
|
255
|
+
"twap"
|
|
256
|
+
]).describe("Order type"),
|
|
257
|
+
size: decimalStringParam.describe('Order size in the base asset, decimal string (e.g. "0.5")'),
|
|
258
|
+
price: decimalStringParam.optional().describe("Limit price, for limit-priced order types"),
|
|
259
|
+
trigger_price: decimalStringParam.optional().describe("Trigger price, for stop and take-profit order types"),
|
|
260
|
+
reduce_only: z2.boolean().optional().describe("Only reduce the current position"),
|
|
261
|
+
leverage: z2.number().int().min(1).max(100).optional().describe("Leverage 1-100; defaults to the account's active leverage"),
|
|
262
|
+
take_profit: decimalStringParam.optional().describe("Attached take-profit price"),
|
|
263
|
+
stop_loss: decimalStringParam.optional().describe("Attached stop-loss price"),
|
|
264
|
+
twap_duration_minutes: z2.number().int().min(5).max(1440).optional().describe("TWAP duration in minutes, 5-1440; required for twap"),
|
|
265
|
+
portfolio_id: portfolioIdParam
|
|
266
|
+
}, async ({
|
|
267
|
+
symbol,
|
|
268
|
+
side,
|
|
269
|
+
order_type,
|
|
270
|
+
size,
|
|
271
|
+
price,
|
|
272
|
+
trigger_price,
|
|
273
|
+
reduce_only,
|
|
274
|
+
leverage,
|
|
275
|
+
take_profit,
|
|
276
|
+
stop_loss,
|
|
277
|
+
twap_duration_minutes,
|
|
278
|
+
portfolio_id
|
|
279
|
+
}) => {
|
|
280
|
+
const result = await client.request("POST", resolve("orders/preview", portfolio_id), undefined, {
|
|
281
|
+
symbol,
|
|
282
|
+
side,
|
|
283
|
+
orderType: order_type,
|
|
284
|
+
size,
|
|
285
|
+
price,
|
|
286
|
+
triggerPrice: trigger_price,
|
|
287
|
+
reduceOnly: reduce_only,
|
|
288
|
+
leverage,
|
|
289
|
+
takeProfit: take_profit,
|
|
290
|
+
stopLoss: stop_loss,
|
|
291
|
+
twapDurationMinutes: twap_duration_minutes
|
|
292
|
+
});
|
|
293
|
+
return jsonResult(result);
|
|
294
|
+
});
|
|
295
|
+
server.tool("perps_get_withdraw_payload", "Step 1 of a perps withdrawal (perps account -> the portfolio's Arbitrum trading vault, in USDC). Returns EIP-712 typedDataJson and its nonce. The payload must be signed by the perps account owner wallet (accountOwnerAddress from perps_get_account_status); this server cannot sign. Pass the signature to perps_submit_withdraw. Requires a WRITE-scoped key.", {
|
|
296
|
+
amount: decimalStringParam.describe('USDC amount to withdraw, decimal string (e.g. "250"); the venue deducts its ~$1 fee from it'),
|
|
297
|
+
destination: evmAddressParam.optional().describe("Arbitrum address to receive the USDC; must be one of the portfolio's Arbitrum trading vaults. Defaults to the portfolio's Arbitrum trading vault"),
|
|
298
|
+
portfolio_id: portfolioIdParam
|
|
299
|
+
}, async ({ amount, destination, portfolio_id }) => {
|
|
300
|
+
const result = await client.request("POST", resolve("withdraw/payload", portfolio_id), undefined, { amount, destination });
|
|
301
|
+
return jsonResult(result);
|
|
302
|
+
});
|
|
303
|
+
server.tool("perps_submit_withdraw", "Step 2 of a perps withdrawal: submit the account owner's signature over the typed data from perps_get_withdraw_payload. amount, destination, and nonce must be exactly the values that step returned. USDC arrives on Arbitrum in about five minutes. Requires a WRITE-scoped key.", {
|
|
304
|
+
amount: decimalStringParam.describe("Exactly the amount returned by perps_get_withdraw_payload"),
|
|
305
|
+
destination: evmAddressParam.describe("Exactly the destination returned by perps_get_withdraw_payload"),
|
|
306
|
+
nonce: epochMsParam().describe("Exactly the nonce returned by perps_get_withdraw_payload"),
|
|
307
|
+
signature: z2.object({
|
|
308
|
+
r: hex32Param,
|
|
309
|
+
s: hex32Param,
|
|
310
|
+
v: z2.union([z2.literal(27), z2.literal(28)])
|
|
311
|
+
}).describe("The account owner's EIP-712 signature split into r, s (0x-prefixed 32-byte hex) and v (27 or 28)"),
|
|
312
|
+
portfolio_id: portfolioIdParam
|
|
313
|
+
}, async ({ amount, destination, nonce, signature, portfolio_id }) => {
|
|
314
|
+
const result = await client.request("POST", resolve("withdraw", portfolio_id), undefined, { amount, destination, nonce, signature });
|
|
315
|
+
return jsonResult(result);
|
|
316
|
+
});
|
|
317
|
+
server.tool("perps_get_deposit_quote", "Step 1 of a perps deposit (trading vault -> perps account). Prices the transfer and returns a quoteId plus toAmount, the amount that lands after routing and gas. No wallet signature is needed. Pass the same fields and the quoteId to perps_deposit. Requires a WRITE-scoped key.", depositFields, async ({
|
|
318
|
+
source_vault_id,
|
|
319
|
+
destination_portfolio_id,
|
|
320
|
+
from_asset_address,
|
|
321
|
+
from_amount,
|
|
322
|
+
portfolio_id
|
|
323
|
+
}) => {
|
|
324
|
+
const result = await client.request("POST", resolve("deposit/vault-fund-hl/quote", portfolio_id), undefined, {
|
|
325
|
+
sourceVaultId: source_vault_id,
|
|
326
|
+
destinationPortfolioId: destination_portfolio_id,
|
|
327
|
+
fromAssetAddress: from_asset_address,
|
|
328
|
+
fromAmount: from_amount
|
|
329
|
+
});
|
|
330
|
+
return jsonResult(result);
|
|
331
|
+
});
|
|
332
|
+
server.tool("perps_deposit", "Step 2 of a perps deposit: execute a quote from perps_get_deposit_quote. Repeat the quote's four fields exactly and add its quoteId. Settles asynchronously and returns a requestId; poll perps_get_account for the new balance. Moves real funds. Requires a WRITE-scoped key.", {
|
|
333
|
+
quote_id: z2.string().min(1).describe("The quoteId returned by perps_get_deposit_quote"),
|
|
334
|
+
...depositFields
|
|
335
|
+
}, async ({
|
|
336
|
+
quote_id,
|
|
337
|
+
source_vault_id,
|
|
338
|
+
destination_portfolio_id,
|
|
339
|
+
from_asset_address,
|
|
340
|
+
from_amount,
|
|
341
|
+
portfolio_id
|
|
342
|
+
}) => {
|
|
343
|
+
const result = await client.request("POST", resolve("deposit/vault-fund-hl", portfolio_id), undefined, {
|
|
344
|
+
quoteId: quote_id,
|
|
345
|
+
sourceVaultId: source_vault_id,
|
|
346
|
+
destinationPortfolioId: destination_portfolio_id,
|
|
347
|
+
fromAssetAddress: from_asset_address,
|
|
348
|
+
fromAmount: from_amount
|
|
349
|
+
});
|
|
350
|
+
return jsonResult(result);
|
|
351
|
+
});
|
|
352
|
+
}
|
|
234
353
|
|
|
235
354
|
|
|
236
355
|
import { z as z3 } from "zod";
|
|
@@ -685,17 +804,23 @@ import { z as z5 } from "zod";
|
|
|
685
804
|
var McpEnvSchema = z5.object({
|
|
686
805
|
DEFINITIVE_API_KEY: z5.string().startsWith("dpka_"),
|
|
687
806
|
DEFINITIVE_API_SECRET: z5.string().startsWith("dpks_"),
|
|
688
|
-
DEFINITIVE_BASE_URL: z5.string().url().
|
|
807
|
+
DEFINITIVE_BASE_URL: z5.string().url().refine((value) => new URL(value).protocol === "https:", {
|
|
808
|
+
message: "DEFINITIVE_BASE_URL must use https"
|
|
809
|
+
}).default("https://ddp.definitive.fi"),
|
|
689
810
|
DEFINITIVE_API_KEY_TYPE: z5.enum(["portfolio", "organization"]),
|
|
690
811
|
DEFINITIVE_PORTFOLIO_ID: z5.string().optional()
|
|
691
812
|
});
|
|
692
813
|
var env = McpEnvSchema.parse(process.env);
|
|
814
|
+
if (new URL(env.DEFINITIVE_BASE_URL).host !== "ddp.definitive.fi") {
|
|
815
|
+
console.error(`Warning: DEFINITIVE_BASE_URL points at ${new URL(env.DEFINITIVE_BASE_URL).host}, not ddp.definitive.fi. Signed requests and your API key id are sent there.`);
|
|
816
|
+
}
|
|
693
817
|
var client = createClient(env.DEFINITIVE_BASE_URL, env.DEFINITIVE_API_KEY, env.DEFINITIVE_API_SECRET);
|
|
694
|
-
var server = new McpServer({ name: "Definitive", version: "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
|
|
818
|
+
var server = new McpServer({ name: "Definitive", version: "1.3.0" }, {
|
|
819
|
+
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 perps (perpetual futures) market data, account state, order previews, and transfers between trading vaults and the perps account. Perps withdrawals need a signature from the perps account owner wallet, which this server cannot produce. 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."
|
|
696
820
|
});
|
|
697
821
|
registerReadTools(server, client, env.DEFINITIVE_API_KEY_TYPE, env.DEFINITIVE_PORTFOLIO_ID);
|
|
698
822
|
registerWriteTools(server, client, env.DEFINITIVE_API_KEY_TYPE, env.DEFINITIVE_PORTFOLIO_ID);
|
|
699
823
|
registerPerpsReadTools(server, client, env.DEFINITIVE_API_KEY_TYPE, env.DEFINITIVE_PORTFOLIO_ID);
|
|
824
|
+
registerPerpsWriteTools(server, client, env.DEFINITIVE_API_KEY_TYPE, env.DEFINITIVE_PORTFOLIO_ID);
|
|
700
825
|
var transport = new StdioServerTransport;
|
|
701
826
|
await server.connect(transport);
|