@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 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().default("https://ddp.definitive.fi"),
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.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."
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@definitive-fi/mcp",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "MCP server for the Definitive on-chain trading platform",
5
5
  "keywords": [
6
6
  "mcp",