Skip to main content
Glama
citrex.ts28.3 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import * as services from "../services/index.js"; import { Environment, OrderType, TimeInForce } from "citrex-sdk/enums"; /** * Registers tools related to the Citrex protocol. * @param server The MCP server instance */ export function registerCitrexTools(server: McpServer) { // Fetches ticker information for one or all markets. server.tool( "citrex_get_tickers", "Fetches ticker information for one or all markets from the Citrex protocol.", { symbol: z.string().optional().describe("Optional. The specific market symbol to fetch the ticker for (e.g., 'BTCperp')."), }, async ({ symbol }) => { try { const formattedSymbol = symbol ? `${symbol.replace(/perp$/, '')}perp` as `${string}perp` : undefined; console.log(`Calling citrexGetTickers with symbol: ${formattedSymbol}`); const tickers = await services.citrexGetTickers(formattedSymbol); return { content: [{ type: "text", text: JSON.stringify(tickers, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching Citrex tickers: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Fetches product information by its identifier (ID or symbol). server.tool( "citrex_get_product", "Fetches product information by its identifier (ID or symbol).", { identifier: z.union([ z.number().int().positive().describe("Numeric product ID (must be a positive integer) (e.g., 1004)"), z.string().min(1).describe("String product symbol (e.g., 'seiprep')") ]).describe("Product identifier: either a numeric ID or a symbol string."), }, async ({ identifier }) => { try { console.log(`Calling citrexGetProduct with identifier: ${identifier}`); const product = await services.citrexGetProduct(identifier); return { content: [{ type: "text", text: JSON.stringify(product, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching Citrex product: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Fetches all products and parses their mark prices. server.tool( "citrex_get_products", "Fetches all products and parses their mark prices.", {}, async () => { try { console.log('Calling citrexGetProducts...'); const products = await services.citrexGetProducts(); return { content: [{ type: "text", text: JSON.stringify(products, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching Citrex products: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Fetches the current server time from the Citrex exchange. server.tool( "citrex_get_server_time", "Fetches the current server time from the Citrex exchange.", {}, async () => { try { console.log('Calling citrexGetServerTime...'); const serverTime = await services.citrexGetServerTime(); return { content: [{ type: "text", text: JSON.stringify(serverTime, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching Citrex server time: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Retrieves the configuration currently used by the Citrex SDK instance. server.tool( "citrex_get_config", "Retrieves the configuration currently used by the Citrex SDK instance.", {}, async () => { try { console.log('Calling citrexGetConfig...'); const config = services.citrexGetConfig(); return { content: [{ type: "text", text: JSON.stringify(config, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching Citrex config: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Fetches the order book for a specific market. server.tool( "citrex_get_order_book", "Fetches the order book for a specific market.", { symbol: z.string().describe("The market symbol to fetch the order book for (e.g., 'seiperp', 'ethperp', 'btcperp')."), }, async ({ symbol }) => { try { const formattedSymbol = `${symbol.replace(/perp$/, '')}perp` as `${string}perp`; console.log(`Calling citrexGetOrderBook with symbol: ${formattedSymbol}`); const orderBook = await services.citrexGetOrderBook(formattedSymbol); return { content: [{ type: "text", text: JSON.stringify(orderBook, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching Citrex order book: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Fetches historical kline (candlestick) data for a product. server.tool( "citrex_get_klines", "Fetches historical kline (candlestick) data for a product.", { productSymbol: z.string().describe("The symbol of the product (e.g., 'seiperp', 'ethperp', 'btcperp')."), optionalArgs: z.object({ startTime: z.number().optional(), endTime: z.number().optional(), limit: z.number().optional(), }).optional().describe("Optional arguments like startTime, endTime, and limit."), }, async ({ productSymbol, optionalArgs }) => { try { const formattedSymbol = `${productSymbol.replace(/perp$/, '')}perp` as `${string}perp`; console.log(`Calling citrexGetKlines with symbol: ${productSymbol}`); const klines = await services.citrexGetKlines(formattedSymbol, optionalArgs); return { content: [{ type: "text", text: JSON.stringify(klines, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching Citrex klines: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Fetches the trade history for a specific product. server.tool( "citrex_get_trade_history", "Fetches the trade history for a specific product.", { productSymbol: z.string().describe("The symbol of the product (e.g., 'seiperp', 'ethperp', 'btcperp')."), quantity: z.number().optional().describe("Optional. The number of trades to fetch."), }, async ({ productSymbol, quantity = 10 }) => { try { const formattedSymbol = `${productSymbol.replace(/perp$/, '')}perp` as `${string}perp`; console.log(`Calling citrexGetTradeHistory with symbol: ${formattedSymbol}`); const tradeHistory = await services.citrexGetTradeHistory(formattedSymbol, quantity); return { content: [{ type: "text", text: JSON.stringify(tradeHistory, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching Citrex trade history: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Fetches the health of the user's account, including margin information. server.tool( "citrex_get_account_health", "Fetches the health of the user's account, including margin information.", {}, async () => { try { console.log('Calling citrexGetAccountHealth...'); const accountHealth = await services.citrexGetAccountHealth(); return { content: [{ type: "text", text: JSON.stringify(accountHealth, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching Citrex account health: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Fetches a list of all asset balances for the user's account. server.tool( "citrex_list_balances", "Fetches a list of all asset balances for the user's account.", {}, async () => { try { console.log('Calling citrexListBalances...'); const balances = await services.citrexListBalances(); return { content: [{ type: "text", text: JSON.stringify(balances, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching Citrex balances: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Lists the user's open orders. server.tool( "citrex_list_open_orders", "Lists the user's open orders.", { productSymbol: z.string().optional().describe("Optional. Filter open orders by a specific market symbol."), }, async ({ productSymbol }) => { try { const formattedSymbol = productSymbol ? `${productSymbol.replace(/perp$/, '')}perp` as `${string}perp` : undefined; console.log(`Calling citrexListOpenOrders... ${formattedSymbol ? `for ${formattedSymbol}` : ''}`); const openOrders = await services.citrexListOpenOrders(formattedSymbol); return { content: [{ type: "text", text: JSON.stringify(openOrders, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching Citrex open orders: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Calculates the margin requirement for a potential trade. server.tool( "citrex_calculate_margin_requirement", "Calculates the margin requirement for a potential trade.", { isBuy: z.boolean().describe("Whether the trade is a buy or sell."), price: z.number().describe("The price of the trade."), productId: z.number().describe("The ID of the product being traded."), quantity: z.number().describe("The quantity of the trade."), }, async ({ isBuy, price, productId, quantity }) => { try { console.log(`Calling citrexCalculateMarginRequirement for productId: ${productId}`); const marginRequirement = await services.citrexCalculateMarginRequirement(isBuy, price, productId, quantity); return { content: [{ type: "text", text: JSON.stringify(marginRequirement, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error calculating Citrex margin requirement: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Deposits funds into the user's Citrex account. server.tool( "citrex_deposit", "Deposits funds into the user's Citrex account.", { amount: z.string().describe("The amount to deposit."), }, async ({ amount }) => { try { console.log(`Calling citrexDeposit with amount: ${amount}`); const result = await services.citrexDeposit(amount); return { content: [{ type: "text", text: JSON.stringify({ message: result }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error during Citrex deposit: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Withdraws funds from the user's Citrex account. server.tool( "citrex_withdraw", "Withdraws funds from the user's Citrex account.", { amount: z.string().describe("The amount to withdraw."), }, async ({ amount }) => { try { console.log(`Calling citrexWithdraw with amount: ${amount}`); const result = await services.citrexWithdraw(amount); return { content: [{ type: "text", text: JSON.stringify({ message: result }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error during Citrex withdrawal: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Places a new order on the Citrex exchange. server.tool( "citrex_place_order", "Places a new order on the Citrex exchange.", { orderArgs: z.object({ isBuy: z.boolean().describe("Whether to buy (true) or sell (false)"), price: z.number().positive().describe("The price of the asset you intend to order."), productId: z.number().int().positive().describe("The product ID of asset"), quantity: z.number().positive().describe("The amount of the asset you intend to order ex. 1, 2"), orderType: z.nativeEnum(OrderType).optional().describe("The type of order (default: MARKET)"), timeInForce: z.nativeEnum(TimeInForce).optional().describe("The time in force for the order (default: FOK)"), expiration: z.number().optional().describe("The expiration time of the order in milliseconds (default: now + 30 days)"), nonce: z.number().optional().describe("A unique identifier for the order (default: current unix timestamp in nano seconds)"), priceIncrement: z.number().optional().describe("The price precision for the product (required for MARKET orders) find it in the product info under the 'increment' key. in wei ex. (10000000000000)"), slippage: z.number().optional().describe("The percentage by which to adjust the price when orderType is MARKET (default: 2.5%)"), }) }, async ({ orderArgs }) => { try { console.log('Calling citrexPlaceOrder...'); const result = await services.citrexPlaceOrder(orderArgs as any); return { content: [{ type: "text", text: JSON.stringify(result, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error placing Citrex order: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Places multiple new orders on the Citrex exchange in a single transaction. server.tool( "citrex_place_orders", "Places multiple new orders on the Citrex exchange in a single transaction.", { ordersArgs: z.array(z.record(z.any())).describe("An array of objects containing the details for each order."), }, async ({ ordersArgs }) => { try { console.log(`Calling citrexPlaceOrders with ${ordersArgs.length} orders...`); const result = await services.citrexPlaceOrders(ordersArgs as any[]); return { content: [{ type: "text", text: JSON.stringify(result, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error placing multiple Citrex orders: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Cancels an existing open order. server.tool( "citrex_cancel_order", "Cancels an existing open order.", { orderId: z.string().describe("The ID of the order to be canceled."), productId: z.number().describe("The ID of the product associated with the order."), }, async ({ orderId, productId }) => { try { console.log(`Calling citrexCancelOrder for orderId: ${orderId}`); const result = await services.citrexCancelOrder(orderId as `0x${string}`, productId); return { content: [{ type: "text", text: JSON.stringify(result, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error canceling Citrex order: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Cancels multiple existing open orders in a single transaction. server.tool( "citrex_cancel_orders", "Cancels multiple existing open orders in a single transaction.", { ordersArgs: z.array(z.tuple([z.string(), z.number()])).describe("An array of tuples, each containing an orderId and productId."), }, async ({ ordersArgs }) => { try { console.log(`Calling citrexCancelOrders with ${ordersArgs.length} orders...`); const result = await services.citrexCancelOrders(ordersArgs as [`0x${string}`, number][]); return { content: [{ type: "text", text: JSON.stringify(result, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error canceling multiple Citrex orders: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Cancels an existing order and replaces it with a new one in a single transaction. server.tool( "citrex_cancel_and_replace_order", "Cancels an existing order and replaces it with a new one in a single transaction.", { orderId: z.string().describe("The ID of the order to be canceled."), orderArgs: z.object({ orderId: z.string().startsWith("0x").describe("The ID of the order to replace"), isBuy: z.boolean().describe("Whether to buy (true) or sell (false)"), price: z.number().positive().describe("The price of the asset you intend to order"), productId: z.number().int().positive().describe("The product ID of asset"), quantity: z.number().positive().describe("The amount of the asset you intend to order"), expiration: z.number().optional().describe("The expiration time of the order in milliseconds (default: now + 30 days)"), nonce: z.number().optional().describe("A unique identifier for the order (default: current unix timestamp in nano seconds)"), }), }, async ({ orderId, orderArgs }) => { try { console.log(`Calling citrexCancelAndReplaceOrder for orderId: ${orderId}`); const result = await services.citrexCancelAndReplaceOrder(orderId as `0x${string}`, orderArgs as any); return { content: [{ type: "text", text: JSON.stringify(result, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error canceling and replacing Citrex order: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Cancels all open orders for a specific product. server.tool( "citrex_cancel_open_orders_for_product", "Cancels all open orders for a specific product.", { productId: z.number().describe("The ID of the product for which to cancel all open orders."), }, async ({ productId }) => { try { console.log(`Calling citrexCancelOpenOrdersForProduct for productId: ${productId}`); const result = await services.citrexCancelOpenOrdersForProduct(productId); return { content: [{ type: "text", text: JSON.stringify(result, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error canceling open orders for product: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Updates the configuration and re-initializes the Citrex SDK instance. server.tool( "citrex_update_config", "Updates the configuration and re-initializes the Citrex SDK instance.", { debug: z.boolean().optional().describe("Whether to enable debug mode."), environment: z.enum(['mainnet', 'testnet']).optional().describe("The environment to use (mainnet or testnet)."), rpc: z.string().optional().describe("The RPC URL to use for the Citrex SDK."), subAccountId: z.number().optional().describe("The sub-account ID to use for the Citrex SDK."), }, async ({ debug = false, environment = 'mainnet', rpc = 'https://evm-rpc.sei-apis.com', subAccountId = 0 }) => { try { console.log('Calling citrexUpdateConfig...'); services.citrexUpdateConfig(debug, environment as Environment, rpc, subAccountId); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: "Citrex config updated successfully." }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error updating Citrex config: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/testinguser1111111/sei-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server