@definitive-fi/mcp 1.0.0 → 1.1.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.
Files changed (3) hide show
  1. package/README.md +5 -1
  2. package/dist/server.js +351 -25
  3. package/package.json +16 -5
package/README.md CHANGED
@@ -22,6 +22,10 @@ Add the following to your MCP client configuration (e.g., Claude Desktop, Claude
22
22
  }
23
23
  ```
24
24
 
25
+ ## Documentation & API Keys
26
+
27
+ New to Definitive? Visit the [Definitive API documentation](https://ddp.definitive.fi/overview) to get started and obtain your API keys.
28
+
25
29
  ## Environment Variables
26
30
 
27
31
  | Variable | Required | Description |
@@ -29,5 +33,5 @@ Add the following to your MCP client configuration (e.g., Claude Desktop, Claude
29
33
  | `DEFINITIVE_API_KEY` | Yes | Your Definitive API key |
30
34
  | `DEFINITIVE_API_SECRET` | Yes | Your Definitive API secret |
31
35
  | `DEFINITIVE_API_KEY_TYPE` | Yes | Key type: `"portfolio"` or `"organization"` |
32
- | `DEFINITIVE_BASE_URL` | No | API base URL (defaults to production) |
36
+ | `DEFINITIVE_BASE_URL` | No | API base URL |
33
37
  | `DEFINITIVE_PORTFOLIO_ID` | No | Portfolio ID (required for organization keys when targeting a specific portfolio) |
package/dist/server.js CHANGED
@@ -120,12 +120,15 @@ var ChainEnum = z.enum([
120
120
  var jsonResult = (result) => ({
121
121
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
122
122
  });
123
+
124
+
125
+ import { z as z2 } from "zod";
123
126
  function registerReadTools(server, client, keyType, defaultPortfolioId) {
124
127
  const resolve = (suffix, portfolioId) => resolvePortfolioRoute(keyType, suffix, portfolioId, defaultPortfolioId);
125
128
  server.tool("list_positions", "List current token holdings in the portfolio with balances, USD values, and P&L.", {
126
- limit: z.number().min(1).max(100).default(20).describe("Max positions to return (1-100)"),
127
- cursor: z.string().optional().describe("Pagination cursor from previous response's nextCursor field"),
128
- include_dust_balances: z.boolean().default(false).describe("Include positions worth less than $1"),
129
+ limit: z2.number().min(1).max(100).default(20).describe("Max positions to return (1-100)"),
130
+ cursor: z2.string().optional().describe("Pagination cursor from previous response's nextCursor field"),
131
+ include_dust_balances: z2.boolean().default(false).describe("Include positions worth less than $1"),
129
132
  portfolio_id: portfolioIdParam
130
133
  }, async ({ limit, cursor, include_dust_balances, portfolio_id }) => {
131
134
  const path = resolve("positions", portfolio_id);
@@ -145,17 +148,17 @@ function registerReadTools(server, client, keyType, defaultPortfolioId) {
145
148
  return jsonResult(result);
146
149
  });
147
150
  server.tool("list_transfers", "List historical transfers (deposits, withdrawals, swaps, bridge transactions) for the portfolio.", {
148
- limit: z.number().min(1).max(100).default(20).describe("Max transfers to return (1-100)"),
149
- cursor: z.string().optional().describe("Pagination cursor from previous response's nextCursor field"),
150
- action_types: z.array(z.enum([
151
+ limit: z2.number().min(1).max(100).default(20).describe("Max transfers to return (1-100)"),
152
+ cursor: z2.string().optional().describe("Pagination cursor from previous response's nextCursor field"),
153
+ action_types: z2.array(z2.enum([
151
154
  "VAULT_ACTION_DEPOSIT",
152
155
  "VAULT_ACTION_WITHDRAW",
153
156
  "VAULT_ACTION_BRIDGE_SEND",
154
157
  "VAULT_ACTION_BRIDGE_RECEIVE",
155
158
  "VAULT_ACTION_SWAP"
156
159
  ])).optional().describe("Filter by transfer action types"),
157
- start_timestamp: z.string().optional().describe("Start of time range (ISO 8601 string)"),
158
- end_timestamp: z.string().optional().describe("End of time range (ISO 8601 string)"),
160
+ start_timestamp: z2.string().datetime().optional().describe("Start of time range (ISO 8601 string, e.g. 2025-01-01T00:00:00Z)"),
161
+ end_timestamp: z2.string().datetime().optional().describe("End of time range (ISO 8601 string, e.g. 2025-01-01T00:00:00Z)"),
159
162
  portfolio_id: portfolioIdParam
160
163
  }, async ({
161
164
  limit,
@@ -180,7 +183,7 @@ function registerReadTools(server, client, keyType, defaultPortfolioId) {
180
183
  });
181
184
  server.tool("get_deposit_address", "Get a deposit address for a specific blockchain. Creates a vault if one doesn't exist for that chain.", {
182
185
  chain: ChainEnum.describe("Blockchain network name"),
183
- wallet_address: z.string().min(1).describe("User's wallet address on this chain — ask the user if not provided"),
186
+ wallet_address: z2.string().min(1).describe("User's wallet address on this chain — ask the user if not provided"),
184
187
  portfolio_id: portfolioIdParam
185
188
  }, async ({ chain, wallet_address, portfolio_id }) => {
186
189
  const path = resolve(`address/${chain}`, portfolio_id);
@@ -189,9 +192,9 @@ function registerReadTools(server, client, keyType, defaultPortfolioId) {
189
192
  return jsonResult(result);
190
193
  });
191
194
  server.tool("list_orders", "List trade orders with optional status filtering. Returns order details including fill status and pricing.", {
192
- limit: z.number().min(1).max(100).default(20).describe("Max orders to return (1-100)"),
193
- cursor: z.string().optional().describe("Pagination cursor from previous response's nextCursor field"),
194
- status: z.enum([
195
+ limit: z2.number().min(1).max(100).default(20).describe("Max orders to return (1-100)"),
196
+ cursor: z2.string().optional().describe("Pagination cursor from previous response's nextCursor field"),
197
+ status: z2.enum([
195
198
  "ORDER_STATUS_PENDING",
196
199
  "ORDER_STATUS_ACCEPTED",
197
200
  "ORDER_STATUS_PARTIALLY_FILLED",
@@ -220,8 +223,8 @@ function registerReadTools(server, client, keyType, defaultPortfolioId) {
220
223
  if (keyType !== "organization")
221
224
  return;
222
225
  server.tool("list_portfolios", "List all portfolios in the organization. Organization API keys only.", {
223
- limit: z.number().min(1).max(100).default(10).describe("Max portfolios to return (1-100)"),
224
- cursor: z.string().optional().describe("Pagination cursor from previous response's nextCursor field")
226
+ limit: z2.number().min(1).max(100).default(10).describe("Max portfolios to return (1-100)"),
227
+ cursor: z2.string().optional().describe("Pagination cursor from previous response's nextCursor field")
225
228
  }, async ({ limit, cursor }) => {
226
229
  const params = { limit: String(limit) };
227
230
  if (cursor)
@@ -231,8 +234,8 @@ function registerReadTools(server, client, keyType, defaultPortfolioId) {
231
234
  });
232
235
  server.tool("get_fees", "Get fee summary for a portfolio over a time period. Organization API keys only.", {
233
236
  portfolio_id: zUUID.describe("Portfolio UUID to get fees for"),
234
- start_timestamp: z.string().optional().describe("Start of time range (ISO 8601 string)"),
235
- end_timestamp: z.string().optional().describe("End of time range (ISO 8601 string)")
237
+ start_timestamp: z2.string().datetime().optional().describe("Start of time range (ISO 8601 string, e.g. 2025-01-01T00:00:00Z)"),
238
+ end_timestamp: z2.string().datetime().optional().describe("End of time range (ISO 8601 string, e.g. 2025-01-01T00:00:00Z)")
236
239
  }, async ({ portfolio_id, start_timestamp, end_timestamp }) => {
237
240
  const params = {};
238
241
  if (start_timestamp)
@@ -245,21 +248,344 @@ function registerReadTools(server, client, keyType, defaultPortfolioId) {
245
248
  }
246
249
 
247
250
 
248
- import { z as z2 } from "zod";
249
- var McpEnvSchema = z2.object({
250
- DEFINITIVE_API_KEY: z2.string().startsWith("dpka_"),
251
- DEFINITIVE_API_SECRET: z2.string().startsWith("dpks_"),
252
- DEFINITIVE_BASE_URL: z2.string().url().default("https://ddp.definitive.fi"),
253
- DEFINITIVE_API_KEY_TYPE: z2.enum(["portfolio", "organization"]),
254
- DEFINITIVE_PORTFOLIO_ID: z2.string().optional()
251
+ import { z as z3 } from "zod";
252
+ var OrderSideEnum = z3.enum(["buy", "sell"]);
253
+ var OrderTypeEnum = z3.enum([
254
+ "market",
255
+ "limit",
256
+ "twap",
257
+ "stop",
258
+ "stop-loss",
259
+ "take-profit"
260
+ ]);
261
+ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
262
+ const resolve = (suffix, portfolioId) => resolvePortfolioRoute(keyType, suffix, portfolioId, defaultPortfolioId);
263
+ 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.", {
264
+ type: OrderTypeEnum.describe("Order type"),
265
+ chain: ChainEnum.describe("Blockchain network name"),
266
+ target_asset: z3.string().min(1).describe("Target asset contract address"),
267
+ contra_asset: z3.string().min(1).describe("Contra (quote) asset contract address"),
268
+ qty: z3.string().min(1).describe("Order quantity as a decimal string"),
269
+ order_side: OrderSideEnum.describe("Buy or sell"),
270
+ limit_price: z3.string().optional().describe("Limit price (for limit orders)"),
271
+ limit_is_notional: z3.boolean().optional().describe("Whether limit price is in notional terms"),
272
+ trigger_price: z3.string().optional().describe("Trigger price (for stop/stop-loss/take-profit orders)"),
273
+ trigger_is_notional: z3.boolean().optional().describe("Whether trigger price is in notional terms"),
274
+ duration_seconds: z3.number().optional().describe("TWAP duration in seconds"),
275
+ target_twap_buckets: z3.number().optional().describe("Number of TWAP buckets"),
276
+ trigger_type: z3.enum(["upper", "lower"]).optional().describe("Trigger type for stop-buy orders only (upper or lower price bound)"),
277
+ slippage_tolerance: z3.string().optional().describe("Slippage tolerance as a decimal string (e.g. '0.01' for 1%)"),
278
+ max_price_impact: z3.string().optional().describe("Max price impact as a decimal string (e.g. '0.01' for 1%)"),
279
+ portfolio_id: portfolioIdParam
280
+ }, { readOnlyHint: true }, async ({
281
+ type,
282
+ chain,
283
+ target_asset,
284
+ contra_asset,
285
+ qty,
286
+ order_side,
287
+ limit_price,
288
+ limit_is_notional,
289
+ trigger_price,
290
+ trigger_is_notional,
291
+ duration_seconds,
292
+ target_twap_buckets,
293
+ trigger_type,
294
+ slippage_tolerance,
295
+ max_price_impact,
296
+ portfolio_id
297
+ }) => {
298
+ const path = resolve("trade/quote", portfolio_id);
299
+ const body = {
300
+ type,
301
+ chain,
302
+ targetAsset: target_asset,
303
+ contraAsset: contra_asset,
304
+ qty,
305
+ orderSide: order_side
306
+ };
307
+ if (limit_price !== undefined) {
308
+ body.limit = {
309
+ price: limit_price,
310
+ isNotional: limit_is_notional ?? false
311
+ };
312
+ }
313
+ if (trigger_price !== undefined) {
314
+ body.trigger = {
315
+ price: trigger_price,
316
+ isNotional: trigger_is_notional ?? false
317
+ };
318
+ }
319
+ if (duration_seconds !== undefined)
320
+ body.durationSeconds = duration_seconds;
321
+ if (target_twap_buckets !== undefined)
322
+ body.targetTWAPBuckets = target_twap_buckets;
323
+ if (trigger_type !== undefined)
324
+ body.triggerType = trigger_type;
325
+ if (slippage_tolerance !== undefined)
326
+ body.slippageTolerance = slippage_tolerance;
327
+ if (max_price_impact !== undefined)
328
+ body.maxPriceImpact = max_price_impact;
329
+ const result = await client.request("POST", path, undefined, body);
330
+ return jsonResult(result);
331
+ });
332
+ 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.", {
333
+ target_asset: z3.string().min(1).describe("Target asset contract address"),
334
+ contra_asset: z3.string().min(1).describe("Contra (quote) asset contract address"),
335
+ chain: ChainEnum.describe("Blockchain network name"),
336
+ qty: z3.string().min(1).describe("Order quantity as a decimal string"),
337
+ order_side: OrderSideEnum.describe("Buy or sell"),
338
+ portfolio_id: portfolioIdParam
339
+ }, { readOnlyHint: true }, async ({
340
+ target_asset,
341
+ contra_asset,
342
+ chain,
343
+ qty,
344
+ order_side,
345
+ portfolio_id
346
+ }) => {
347
+ const path = resolve("quicktrade/quote", portfolio_id);
348
+ const body = {
349
+ type: "market",
350
+ chain,
351
+ targetAsset: target_asset,
352
+ contraAsset: contra_asset,
353
+ qty,
354
+ orderSide: order_side
355
+ };
356
+ const result = await client.request("POST", path, undefined, body);
357
+ return jsonResult(result);
358
+ });
359
+ 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.", {
360
+ from_asset_address: z3.string().min(1).describe("Source asset contract address"),
361
+ from_chain: ChainEnum.describe("Source blockchain network"),
362
+ to_asset_address: z3.string().min(1).describe("Destination asset contract address"),
363
+ to_chain: ChainEnum.describe("Destination blockchain network"),
364
+ from_amount: z3.string().min(1).describe("Amount to bridge as a decimal string"),
365
+ portfolio_id: portfolioIdParam
366
+ }, { readOnlyHint: true }, async ({
367
+ from_asset_address,
368
+ from_chain,
369
+ to_asset_address,
370
+ to_chain,
371
+ from_amount,
372
+ portfolio_id
373
+ }) => {
374
+ const path = resolve("bridge/quote", portfolio_id);
375
+ const body = {
376
+ fromAssetAddress: from_asset_address,
377
+ fromChain: from_chain,
378
+ toAssetAddress: to_asset_address,
379
+ toChain: to_chain,
380
+ fromAmount: from_amount
381
+ };
382
+ const result = await client.request("POST", path, undefined, body);
383
+ return jsonResult(result);
384
+ });
385
+ server.tool("cancel_trade", "Cancel a pending trade order. This prevents the order from executing.", {
386
+ order_id: zUUID.describe("The order UUID to cancel"),
387
+ portfolio_id: portfolioIdParam
388
+ }, {
389
+ readOnlyHint: false,
390
+ destructiveHint: false
391
+ }, async ({ order_id, portfolio_id }) => {
392
+ const path = resolve(`trade/${order_id}`, portfolio_id);
393
+ const result = await client.request("DELETE", path);
394
+ return jsonResult(result);
395
+ });
396
+ server.tool("cancel_quicktrade", "Cancel a pending QuickTrade order. This prevents the order from executing.", {
397
+ order_id: zUUID.describe("The order UUID to cancel"),
398
+ portfolio_id: portfolioIdParam
399
+ }, {
400
+ readOnlyHint: false,
401
+ destructiveHint: false
402
+ }, async ({ order_id, portfolio_id }) => {
403
+ const path = resolve(`quicktrade/${order_id}`, portfolio_id);
404
+ const result = await client.request("DELETE", path);
405
+ return jsonResult(result);
406
+ });
407
+ 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.", {
408
+ quote_id: zUUID.describe("Quote UUID from get_trade_quote response (found in quote.quote.id)"),
409
+ type: OrderTypeEnum.describe("Order type"),
410
+ chain: ChainEnum.describe("Blockchain network name"),
411
+ target_asset: z3.string().min(1).describe("Target asset contract address"),
412
+ contra_asset: z3.string().min(1).describe("Contra (quote) asset contract address"),
413
+ qty: z3.string().min(1).describe("Order quantity as a decimal string"),
414
+ order_side: OrderSideEnum.describe("Buy or sell"),
415
+ limit_price: z3.string().optional().describe("Limit price (for limit orders)"),
416
+ limit_is_notional: z3.boolean().optional().describe("Whether limit price is in notional terms"),
417
+ trigger_price: z3.string().optional().describe("Trigger price (for stop/stop-loss/take-profit orders)"),
418
+ trigger_is_notional: z3.boolean().optional().describe("Whether trigger price is in notional terms"),
419
+ duration_seconds: z3.number().optional().describe("TWAP duration in seconds"),
420
+ target_twap_buckets: z3.number().optional().describe("Number of TWAP buckets"),
421
+ trigger_type: z3.enum(["upper", "lower"]).optional().describe("Trigger type for stop-buy orders only"),
422
+ slippage_tolerance: z3.string().optional().describe("Slippage tolerance as a decimal string (e.g. '0.01' for 1%)"),
423
+ max_price_impact: z3.string().optional().describe("Max price impact as a decimal string (e.g. '0.01' for 1%)"),
424
+ portfolio_id: portfolioIdParam
425
+ }, {
426
+ readOnlyHint: false,
427
+ destructiveHint: true,
428
+ idempotentHint: false
429
+ }, async ({
430
+ quote_id,
431
+ type,
432
+ chain,
433
+ target_asset,
434
+ contra_asset,
435
+ qty,
436
+ order_side,
437
+ limit_price,
438
+ limit_is_notional,
439
+ trigger_price,
440
+ trigger_is_notional,
441
+ duration_seconds,
442
+ target_twap_buckets,
443
+ trigger_type,
444
+ slippage_tolerance,
445
+ max_price_impact,
446
+ portfolio_id
447
+ }) => {
448
+ const path = resolve("trade", portfolio_id);
449
+ const externalOrderRequest = {
450
+ type,
451
+ chain,
452
+ targetAsset: target_asset,
453
+ contraAsset: contra_asset,
454
+ qty,
455
+ orderSide: order_side
456
+ };
457
+ if (limit_price !== undefined)
458
+ externalOrderRequest.limit = {
459
+ price: limit_price,
460
+ isNotional: limit_is_notional ?? false
461
+ };
462
+ if (trigger_price !== undefined)
463
+ externalOrderRequest.trigger = {
464
+ price: trigger_price,
465
+ isNotional: trigger_is_notional ?? false
466
+ };
467
+ if (duration_seconds !== undefined)
468
+ externalOrderRequest.durationSeconds = duration_seconds;
469
+ if (target_twap_buckets !== undefined)
470
+ externalOrderRequest.targetTWAPBuckets = target_twap_buckets;
471
+ if (trigger_type !== undefined)
472
+ externalOrderRequest.triggerType = trigger_type;
473
+ if (slippage_tolerance !== undefined)
474
+ externalOrderRequest.slippageTolerance = slippage_tolerance;
475
+ if (max_price_impact !== undefined)
476
+ externalOrderRequest.maxPriceImpact = max_price_impact;
477
+ const result = await client.request("POST", path, undefined, {
478
+ quoteId: quote_id,
479
+ externalOrderRequest
480
+ });
481
+ return jsonResult(result);
482
+ });
483
+ 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.", {
484
+ target_asset: z3.string().min(1).describe("Target asset contract address"),
485
+ contra_asset: z3.string().min(1).describe("Contra (quote) asset contract address"),
486
+ chain: ChainEnum.describe("Blockchain network name"),
487
+ qty: z3.string().min(1).describe("Order quantity as a decimal string"),
488
+ order_side: OrderSideEnum.describe("Buy or sell"),
489
+ slippage_tolerance: z3.string().optional().describe("Slippage tolerance as a decimal string (e.g. '0.01' for 1%)"),
490
+ display_asset_price: z3.string().optional().describe("Target asset notional price for display validation"),
491
+ seconds_to_expire: z3.number().int().positive().optional().describe("Order expiry time in seconds"),
492
+ portfolio_id: portfolioIdParam
493
+ }, {
494
+ readOnlyHint: false,
495
+ destructiveHint: true,
496
+ idempotentHint: false
497
+ }, async ({
498
+ target_asset,
499
+ contra_asset,
500
+ chain,
501
+ qty,
502
+ order_side,
503
+ slippage_tolerance,
504
+ display_asset_price,
505
+ seconds_to_expire,
506
+ portfolio_id
507
+ }) => {
508
+ const path = resolve("quicktrade", portfolio_id);
509
+ const body = {
510
+ type: "market",
511
+ chain,
512
+ targetAsset: target_asset,
513
+ contraAsset: contra_asset,
514
+ qty,
515
+ orderSide: order_side
516
+ };
517
+ if (slippage_tolerance !== undefined)
518
+ body.slippageTolerance = slippage_tolerance;
519
+ if (display_asset_price !== undefined)
520
+ body.displayAssetPrice = display_asset_price;
521
+ if (seconds_to_expire !== undefined)
522
+ body.secondsToExpire = seconds_to_expire;
523
+ const result = await client.request("POST", path, undefined, body);
524
+ return jsonResult(result);
525
+ });
526
+ 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.", {
527
+ from_chain: ChainEnum.describe("Source blockchain network"),
528
+ to_chain: ChainEnum.describe("Destination blockchain network"),
529
+ from_asset_address: z3.string().min(1).describe("Source asset contract address"),
530
+ to_asset_address: z3.string().min(1).describe("Destination asset contract address"),
531
+ from_amount: z3.string().min(1).describe("Amount to bridge as a decimal string"),
532
+ route_id: z3.string().min(1).describe("Route ID from bridge_quote response"),
533
+ portfolio_id: portfolioIdParam
534
+ }, {
535
+ readOnlyHint: false,
536
+ destructiveHint: true,
537
+ idempotentHint: false
538
+ }, async ({
539
+ from_chain,
540
+ to_chain,
541
+ from_asset_address,
542
+ to_asset_address,
543
+ from_amount,
544
+ route_id,
545
+ portfolio_id
546
+ }) => {
547
+ const path = resolve("bridge", portfolio_id);
548
+ const body = {
549
+ fromChain: from_chain,
550
+ toChain: to_chain,
551
+ fromAssetAddress: from_asset_address,
552
+ toAssetAddress: to_asset_address,
553
+ fromAmount: from_amount,
554
+ routeId: route_id
555
+ };
556
+ const result = await client.request("POST", path, undefined, body);
557
+ return jsonResult(result);
558
+ });
559
+ if (keyType !== "organization")
560
+ return;
561
+ server.tool("create_portfolio", "Create a new portfolio in the organization. Organization API keys only.", {
562
+ portfolio_name: z3.string().min(1).describe("Name for the new portfolio")
563
+ }, {
564
+ readOnlyHint: false,
565
+ destructiveHint: false
566
+ }, async ({ portfolio_name }) => {
567
+ const result = await client.request("POST", "/v2/organization/create-portfolio", undefined, { portfolioName: portfolio_name });
568
+ return jsonResult(result);
569
+ });
570
+ }
571
+
572
+
573
+ import { z as z4 } from "zod";
574
+ var McpEnvSchema = z4.object({
575
+ DEFINITIVE_API_KEY: z4.string().startsWith("dpka_"),
576
+ DEFINITIVE_API_SECRET: z4.string().startsWith("dpks_"),
577
+ DEFINITIVE_BASE_URL: z4.string().url().default("https://ddp.definitive.fi"),
578
+ DEFINITIVE_API_KEY_TYPE: z4.enum(["portfolio", "organization"]),
579
+ DEFINITIVE_PORTFOLIO_ID: z4.string().optional()
255
580
  });
256
581
  var env = McpEnvSchema.parse(process.env);
257
582
  var client = createClient(env.DEFINITIVE_BASE_URL, env.DEFINITIVE_API_KEY, env.DEFINITIVE_API_SECRET);
258
583
  var server = new McpServer({
259
584
  name: "Definitive",
260
- version: "1.0.0",
261
- 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 11 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. IMPORTANT: When specifying asset addresses for EVM native assets (ETH, MATIC, AVAX, BNB, HYPE, etc.), use the zero address: 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"
585
+ version: "1.1.1",
586
+ 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."
262
587
  });
263
588
  registerReadTools(server, client, env.DEFINITIVE_API_KEY_TYPE, env.DEFINITIVE_PORTFOLIO_ID);
589
+ registerWriteTools(server, client, env.DEFINITIVE_API_KEY_TYPE, env.DEFINITIVE_PORTFOLIO_ID);
264
590
  var transport = new StdioServerTransport;
265
591
  await server.connect(transport);
package/package.json CHANGED
@@ -1,20 +1,31 @@
1
1
  {
2
2
  "name": "@definitive-fi/mcp",
3
- "version": "1.0.0",
3
+ "version": "1.1.1",
4
4
  "description": "MCP server for the Definitive on-chain trading platform",
5
+ "keywords": [
6
+ "mcp",
7
+ "definitive",
8
+ "trading",
9
+ "defi",
10
+ "crypto",
11
+ "blockchain",
12
+ "onchain"
13
+ ],
5
14
  "type": "module",
6
15
  "bin": "dist/server.js",
7
16
  "files": [
8
17
  "dist"
9
18
  ],
10
19
  "scripts": {
11
- "build": "bun run build.ts"
12
- },
13
- "engines": {
14
- "node": ">=18"
20
+ "build": "bun run build.ts",
21
+ "dev": "bun run --hot src/server.ts",
22
+ "start": "bun run src/server.ts"
15
23
  },
16
24
  "dependencies": {
17
25
  "@modelcontextprotocol/sdk": "^1.27.1",
18
26
  "zod": "^3.25.0"
27
+ },
28
+ "engines": {
29
+ "node": ">=18"
19
30
  }
20
31
  }