@definitive-fi/mcp 1.2.0 → 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 +155 -31
- 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
|
@@ -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,29 +115,16 @@ 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
|
-
"ink"
|
|
121
|
-
]);
|
|
118
|
+
var chainParam = (label) => z.string().min(1).describe(`${label}, lowercase (e.g. ethereum, base, arbitrum, solana)`);
|
|
122
119
|
var jsonResult = (result) => ({
|
|
123
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
120
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
121
|
+
...isErrorResult(result) && { isError: true }
|
|
124
122
|
});
|
|
123
|
+
var isErrorResult = (result) => typeof result === "object" && result !== null && ("error" in result) && result.error === true;
|
|
125
124
|
|
|
126
125
|
|
|
127
126
|
import { z as z2 } from "zod";
|
|
128
|
-
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');
|
|
129
128
|
var MIN_EPOCH_MS = 1600000000000;
|
|
130
129
|
var MAX_EPOCH_MS = 4102444800000;
|
|
131
130
|
var epochMsParam = () => z2.number().int().min(MIN_EPOCH_MS).max(MAX_EPOCH_MS);
|
|
@@ -232,6 +231,125 @@ function registerPerpsReadTools(server, client, keyType, defaultPortfolioId) {
|
|
|
232
231
|
return jsonResult(result);
|
|
233
232
|
});
|
|
234
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
|
+
}
|
|
235
353
|
|
|
236
354
|
|
|
237
355
|
import { z as z3 } from "zod";
|
|
@@ -294,7 +412,7 @@ function registerReadTools(server, client, keyType, defaultPortfolioId) {
|
|
|
294
412
|
return jsonResult(result);
|
|
295
413
|
});
|
|
296
414
|
server.tool("get_deposit_address", "Get a deposit address for a specific blockchain. Creates a vault if one doesn't exist for that chain.", {
|
|
297
|
-
chain:
|
|
415
|
+
chain: chainParam("Blockchain network name"),
|
|
298
416
|
wallet_address: z3.string().min(1).describe("User's wallet address on this chain — ask the user if not provided"),
|
|
299
417
|
portfolio_id: portfolioIdParam
|
|
300
418
|
}, async ({ chain, wallet_address, portfolio_id }) => {
|
|
@@ -374,7 +492,7 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
374
492
|
const resolve = (suffix, portfolioId) => resolvePortfolioRoute(keyType, suffix, portfolioId, defaultPortfolioId);
|
|
375
493
|
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.", {
|
|
376
494
|
type: OrderTypeEnum.describe("Order type"),
|
|
377
|
-
chain:
|
|
495
|
+
chain: chainParam("Blockchain network name"),
|
|
378
496
|
target_asset: z4.string().min(1).describe("Target asset contract address"),
|
|
379
497
|
contra_asset: z4.string().min(1).describe("Contra (quote) asset contract address"),
|
|
380
498
|
qty: z4.string().min(1).describe("Order quantity as a decimal string"),
|
|
@@ -444,7 +562,7 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
444
562
|
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.", {
|
|
445
563
|
target_asset: z4.string().min(1).describe("Target asset contract address"),
|
|
446
564
|
contra_asset: z4.string().min(1).describe("Contra (quote) asset contract address"),
|
|
447
|
-
chain:
|
|
565
|
+
chain: chainParam("Blockchain network name"),
|
|
448
566
|
qty: z4.string().min(1).describe("Order quantity as a decimal string"),
|
|
449
567
|
order_side: OrderSideEnum.describe("Buy or sell"),
|
|
450
568
|
portfolio_id: portfolioIdParam
|
|
@@ -470,9 +588,9 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
470
588
|
});
|
|
471
589
|
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.", {
|
|
472
590
|
from_asset_address: z4.string().min(1).describe("Source asset contract address"),
|
|
473
|
-
from_chain:
|
|
591
|
+
from_chain: chainParam("Source blockchain network"),
|
|
474
592
|
to_asset_address: z4.string().min(1).describe("Destination asset contract address"),
|
|
475
|
-
to_chain:
|
|
593
|
+
to_chain: chainParam("Destination blockchain network"),
|
|
476
594
|
from_amount: z4.string().min(1).describe("Amount to bridge as a decimal string"),
|
|
477
595
|
portfolio_id: portfolioIdParam
|
|
478
596
|
}, { readOnlyHint: true }, async ({
|
|
@@ -519,7 +637,7 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
519
637
|
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.", {
|
|
520
638
|
quote_id: zUUID.describe("Quote UUID from get_trade_quote response (found in quote.quote.id)"),
|
|
521
639
|
type: OrderTypeEnum.describe("Order type"),
|
|
522
|
-
chain:
|
|
640
|
+
chain: chainParam("Blockchain network name"),
|
|
523
641
|
target_asset: z4.string().min(1).describe("Target asset contract address"),
|
|
524
642
|
contra_asset: z4.string().min(1).describe("Contra (quote) asset contract address"),
|
|
525
643
|
qty: z4.string().min(1).describe("Order quantity as a decimal string"),
|
|
@@ -595,7 +713,7 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
595
713
|
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.", {
|
|
596
714
|
target_asset: z4.string().min(1).describe("Target asset contract address"),
|
|
597
715
|
contra_asset: z4.string().min(1).describe("Contra (quote) asset contract address"),
|
|
598
|
-
chain:
|
|
716
|
+
chain: chainParam("Blockchain network name"),
|
|
599
717
|
qty: z4.string().min(1).describe("Order quantity as a decimal string"),
|
|
600
718
|
order_side: OrderSideEnum.describe("Buy or sell"),
|
|
601
719
|
slippage_tolerance: z4.string().optional().describe("Slippage tolerance as a decimal string (e.g. '0.01' for 1%)"),
|
|
@@ -636,8 +754,8 @@ function registerWriteTools(server, client, keyType, defaultPortfolioId) {
|
|
|
636
754
|
return jsonResult(result);
|
|
637
755
|
});
|
|
638
756
|
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.", {
|
|
639
|
-
from_chain:
|
|
640
|
-
to_chain:
|
|
757
|
+
from_chain: chainParam("Source blockchain network"),
|
|
758
|
+
to_chain: chainParam("Destination blockchain network"),
|
|
641
759
|
from_asset_address: z4.string().min(1).describe("Source asset contract address"),
|
|
642
760
|
to_asset_address: z4.string().min(1).describe("Destination asset contract address"),
|
|
643
761
|
from_amount: z4.string().min(1).describe("Amount to bridge as a decimal string"),
|
|
@@ -686,17 +804,23 @@ import { z as z5 } from "zod";
|
|
|
686
804
|
var McpEnvSchema = z5.object({
|
|
687
805
|
DEFINITIVE_API_KEY: z5.string().startsWith("dpka_"),
|
|
688
806
|
DEFINITIVE_API_SECRET: z5.string().startsWith("dpks_"),
|
|
689
|
-
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"),
|
|
690
810
|
DEFINITIVE_API_KEY_TYPE: z5.enum(["portfolio", "organization"]),
|
|
691
811
|
DEFINITIVE_PORTFOLIO_ID: z5.string().optional()
|
|
692
812
|
});
|
|
693
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
|
+
}
|
|
694
817
|
var client = createClient(env.DEFINITIVE_BASE_URL, env.DEFINITIVE_API_KEY, env.DEFINITIVE_API_SECRET);
|
|
695
|
-
var server = new McpServer({ name: "Definitive", version: "1.
|
|
696
|
-
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."
|
|
697
820
|
});
|
|
698
821
|
registerReadTools(server, client, env.DEFINITIVE_API_KEY_TYPE, env.DEFINITIVE_PORTFOLIO_ID);
|
|
699
822
|
registerWriteTools(server, client, env.DEFINITIVE_API_KEY_TYPE, env.DEFINITIVE_PORTFOLIO_ID);
|
|
700
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);
|
|
701
825
|
var transport = new StdioServerTransport;
|
|
702
826
|
await server.connect(transport);
|