@tamago-labs/okx-dex-mcp
Version:
MCP server for OKX DEX Analytics - comprehensive DEX aggregator analytics with multi-chain support
865 lines (851 loc) • 29.2 kB
JavaScript
;
// src/index.ts
var import_config6 = require("dotenv/config");
// src/config.ts
var import_zod = require("zod");
var SUPPORTED_CHAINS = {
// EVM Chains
ETHEREUM: "1",
OPTIMISM: "10",
BSC: "56",
OKT: "66",
UNI_CHAIN: "130",
SONIC: "146",
X_LAYER: "196",
POLYGON: "137",
ARBITRUM: "42161",
AVALANCHE: "43114",
ZKSYNC: "324",
POLYGON_ZKEVM: "1101",
BASE: "8453",
LINEA: "59144",
FANTOM: "250",
MANTLE: "5000",
CONFLUX: "1030",
METIS: "1088",
MERLIN: "4200",
BLAST: "81457",
MANTA: "169",
SCROLL: "534352",
CRONOS: "25",
ZETA: "7000",
// Non-EVM Chains
TRON: "195",
SOLANA: "501",
SUI: "784",
TON: "607"
};
var QuoteParamsSchema = import_zod.z.object({
chainId: import_zod.z.string().describe("Chain ID"),
fromTokenAddress: import_zod.z.string().describe("Source token contract address"),
toTokenAddress: import_zod.z.string().describe("Destination token contract address"),
amount: import_zod.z.string().describe("Amount to swap in smallest unit"),
slippage: import_zod.z.string().default("0.005").describe("Slippage tolerance (e.g., '0.005' for 0.5%)")
});
var ChainInfoParamsSchema = import_zod.z.object({
chainId: import_zod.z.string().optional().describe("Chain ID to get information for")
});
var LiquidityParamsSchema = import_zod.z.object({
chainId: import_zod.z.string().describe("Chain ID to get liquidity for")
});
var CompareQuotesParamsSchema = import_zod.z.object({
fromTokenAddress: import_zod.z.string().describe("Source token contract address"),
toTokenAddress: import_zod.z.string().describe("Destination token contract address"),
amount: import_zod.z.string().describe("Amount to swap in smallest unit"),
chainIds: import_zod.z.array(import_zod.z.string()).describe("List of chain IDs to compare")
});
function validateEnvironment() {
try {
const required = ["OKX_API_KEY", "OKX_SECRET_KEY", "OKX_API_PASSPHRASE", "OKX_PROJECT_ID"];
const missing = required.filter((key) => !process.env[key]);
if (missing.length > 0) {
console.error(`\u274C Missing required environment variables: ${missing.join(", ")}`);
console.error(`\u{1F4A1} Please set the following in your .env file:`);
missing.forEach((key) => {
console.error(` ${key}=your_${key.toLowerCase()}`);
});
throw new Error("Missing required OKX API credentials");
}
console.error("\u2705 OKX API credentials found in environment");
} catch (error) {
console.error("\u274C Invalid environment configuration:", error);
throw error;
}
}
function getEnvironmentConfig() {
validateEnvironment();
return {
apiKey: process.env.OKX_API_KEY,
secretKey: process.env.OKX_SECRET_KEY,
apiPassphrase: process.env.OKX_API_PASSPHRASE,
projectId: process.env.OKX_PROJECT_ID
};
}
// src/index.ts
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
// src/agent/analytics.ts
var import_okx_dex_sdk = require("@okx-dex/okx-dex-sdk");
// src/types.ts
var OKXDEXError = class extends Error {
constructor(message, code, details) {
super(message);
this.name = "OKXDEXError";
this.code = code;
this.details = details;
}
};
// src/agent/analytics.ts
var OKXDEXAnalyticsAgent = class {
constructor(environment) {
this.environment = environment;
this.client = new import_okx_dex_sdk.OKXDexClient({
apiKey: environment.apiKey,
secretKey: environment.secretKey,
apiPassphrase: environment.apiPassphrase,
projectId: environment.projectId
});
}
/**
* Get quote for token swap
*/
async getQuote(chainId, fromTokenAddress, toTokenAddress, amount, slippage = "0.005") {
try {
const response = await this.client.dex.getQuote({
chainId,
fromTokenAddress,
toTokenAddress,
amount,
slippage
});
if (response.code !== "0" || !response.data || response.data.length === 0) {
throw new OKXDEXError(`Quote request failed: ${response.msg}`, response.code);
}
const quoteData = response.data[0];
return {
chainId: quoteData.chainId,
fromToken: {
address: quoteData.fromToken.tokenContractAddress,
symbol: quoteData.fromToken.tokenSymbol,
decimals: quoteData.fromToken.decimal,
unitPrice: quoteData.fromToken.tokenUnitPrice
},
toToken: {
address: quoteData.toToken.tokenContractAddress,
symbol: quoteData.toToken.tokenSymbol,
decimals: quoteData.toToken.decimal,
unitPrice: quoteData.toToken.tokenUnitPrice
},
fromAmount: quoteData.fromTokenAmount,
toAmount: quoteData.toTokenAmount,
estimatedGas: quoteData.estimateGasFee,
priceImpact: quoteData.priceImpactPercentage,
dexRouters: quoteData.dexRouterList.map((router) => ({
router: router.router,
percent: router.routerPercent,
subRouters: router.subRouterList.map((sub) => ({
dexProtocol: sub.dexProtocol
}))
})),
quoteCompare: quoteData.quoteCompareList || [],
tradeFee: quoteData.tradeFee,
timestamp: Date.now()
};
} catch (error) {
if (error instanceof OKXDEXError) {
throw error;
}
throw new OKXDEXError(`Failed to get quote: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
/**
* Get liquidity information for a chain
*/
async getLiquidity(chainId) {
try {
const response = await this.client.dex.getLiquidity(chainId);
if (response.code !== "0" || !response.data) {
throw new OKXDEXError(`Liquidity request failed: ${response.msg}`, response.code);
}
return {
chainId,
chainName: this.getChainName(chainId),
liquiditySources: response.data
};
} catch (error) {
if (error instanceof OKXDEXError) {
throw error;
}
throw new OKXDEXError(`Failed to get liquidity: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
/**
* Get chain information
*/
async getChainInfo(chainId) {
try {
if (chainId) {
const response = await this.client.dex.getChainData(chainId);
if (response.code !== "0" || !response.data || response.data.length === 0) {
throw new OKXDEXError(`Chain info request failed: ${response.msg}`, response.code);
}
return response.data[0];
} else {
const chainInfos = [];
const supportedChainIds = Object.values(SUPPORTED_CHAINS);
for (const id of supportedChainIds.slice(0, 10)) {
try {
const info = await this.getChainInfo(id);
chainInfos.push(info);
await new Promise((resolve) => setTimeout(resolve, 100));
} catch (error) {
console.warn(`Failed to get info for chain ${id}:`, error);
}
}
return chainInfos;
}
} catch (error) {
if (error instanceof OKXDEXError) {
throw error;
}
throw new OKXDEXError(`Failed to get chain info: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
/**
* Compare quotes across multiple chains for the same token pair
*/
async compareMultiChainQuotes(fromTokenAddress, toTokenAddress, amount, chainIds) {
const results = [];
for (const chainId of chainIds) {
try {
const quote = await this.getQuote(
chainId,
fromTokenAddress,
toTokenAddress,
amount
);
results.push({
chainId,
chainName: this.getChainName(chainId),
quote
});
await new Promise((resolve) => setTimeout(resolve, 200));
} catch (error) {
results.push({
chainId,
chainName: this.getChainName(chainId),
error: error instanceof Error ? error.message : "Unknown error"
});
}
}
return results;
}
/**
* Get market summary with available chains
*/
async getMarketSummary() {
try {
const supportedChainsList = Object.entries(SUPPORTED_CHAINS).map(([name, id]) => ({
chainId: id,
chainName: name.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, (l) => l.toUpperCase()),
isEVM: !["501", "784", "607", "195"].includes(id)
// Non-EVM chains
}));
return {
supportedChains: supportedChainsList.length,
availableChains: supportedChainsList,
timestamp: Date.now()
};
} catch (error) {
if (error instanceof OKXDEXError) {
throw error;
}
throw new OKXDEXError(`Failed to get market summary: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
/**
* Get tokens from quotes (since there's no direct token list endpoint)
*/
async getPopularTokenPairs(chainId) {
try {
const commonTokens = {
"1": [
// Ethereum
{ address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", symbol: "ETH" },
{ address: "0xA0b86a33E6417f84bDD9F42DD3a24b1A7FB5Ce15", symbol: "USDC" },
{ address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", symbol: "USDT" }
],
"137": [
// Polygon
{ address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", symbol: "MATIC" },
{ address: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", symbol: "USDC" },
{ address: "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", symbol: "USDT" }
],
"8453": [
// Base
{ address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", symbol: "ETH" },
{ address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", symbol: "USDC" }
]
};
const tokens = commonTokens[chainId] || commonTokens["1"];
const pairs = [];
for (let i = 0; i < tokens.length - 1; i++) {
try {
const quote = await this.getQuote(
chainId,
tokens[i].address,
tokens[i + 1].address,
"1000000000000000000"
// 1 token
);
pairs.push({
fromToken: quote.fromToken,
toToken: quote.toToken,
priceImpact: quote.priceImpact
});
await new Promise((resolve) => setTimeout(resolve, 200));
} catch (error) {
console.warn(`Failed to get quote for ${tokens[i].symbol}/${tokens[i + 1].symbol}:`, error);
}
}
return pairs;
} catch (error) {
throw new OKXDEXError(`Failed to get popular token pairs: ${error instanceof Error ? error.message : "Unknown error"}`);
}
}
/**
* Helper method to get chain name from ID
*/
getChainName(chainId) {
const chainNames = {
"1": "Ethereum",
"10": "Optimism",
"56": "BSC",
"66": "OKT Chain",
"130": "Uni Chain",
"146": "Sonic",
"196": "X Layer",
"137": "Polygon",
"42161": "Arbitrum",
"43114": "Avalanche",
"324": "zkSync Era",
"1101": "Polygon zkEVM",
"8453": "Base",
"59144": "Linea",
"250": "Fantom",
"5000": "Mantle",
"1030": "Conflux",
"1088": "Metis",
"4200": "Merlin Chain",
"81457": "Blast",
"169": "Manta Pacific",
"534352": "Scroll",
"25": "Cronos",
"7000": "Zeta Chain",
"195": "Tron",
"501": "Solana",
"784": "SUI",
"607": "TON"
};
return chainNames[chainId] || `Chain ${chainId}`;
}
};
// src/mcp/quote/get_quote_tools.ts
var GetQuoteTool = {
name: "get_okx_quote",
description: "Get swap quote from OKX DEX aggregator for token pairs across multiple chains",
schema: {
chainId: QuoteParamsSchema.shape.chainId,
fromTokenAddress: QuoteParamsSchema.shape.fromTokenAddress,
toTokenAddress: QuoteParamsSchema.shape.toTokenAddress,
amount: QuoteParamsSchema.shape.amount,
slippage: QuoteParamsSchema.shape.slippage
},
handler: async (agent, params) => {
const validatedParams = QuoteParamsSchema.parse(params);
const result = await agent.getQuote(
validatedParams.chainId,
validatedParams.fromTokenAddress,
validatedParams.toTokenAddress,
validatedParams.amount,
validatedParams.slippage
);
return {
status: "success",
data: result
};
}
};
var CompareMultiChainQuotesTool = {
name: "compare_multichain_quotes",
description: "Compare quotes for the same token pair across multiple chains",
schema: {
fromTokenAddress: CompareQuotesParamsSchema.shape.fromTokenAddress,
toTokenAddress: CompareQuotesParamsSchema.shape.toTokenAddress,
amount: CompareQuotesParamsSchema.shape.amount,
chainIds: CompareQuotesParamsSchema.shape.chainIds
},
handler: async (agent, params) => {
const validatedParams = CompareQuotesParamsSchema.parse(params);
const result = await agent.compareMultiChainQuotes(
validatedParams.fromTokenAddress,
validatedParams.toTokenAddress,
validatedParams.amount,
validatedParams.chainIds
);
return {
status: "success",
data: result
};
}
};
var GetPopularTokenPairsTool = {
name: "get_okx_popular_token_pairs",
description: "Get popular token pairs and their quotes for a specific chain",
schema: {
chainId: QuoteParamsSchema.shape.chainId
},
handler: async (agent, params) => {
const { chainId } = params;
const result = await agent.getPopularTokenPairs(chainId);
return {
status: "success",
data: result
};
}
};
// src/mcp/liquidity/get_liquidity_tools.ts
var GetLiquidityTool = {
name: "get_okx_liquidity",
description: "Get liquidity sources for a specific chain from OKX DEX",
schema: {
chainId: LiquidityParamsSchema.shape.chainId
},
handler: async (agent, params) => {
const validatedParams = LiquidityParamsSchema.parse(params);
const result = await agent.getLiquidity(validatedParams.chainId);
return {
status: "success",
data: result
};
}
};
var GetMultiChainLiquidityTool = {
name: "get_okx_multichain_liquidity",
description: "Get liquidity information across multiple chains for comparison",
schema: {
chainIds: {
type: "array",
items: { type: "string" },
description: "List of chain IDs to get liquidity for",
default: ["1", "137", "8453"]
}
},
handler: async (agent, params) => {
const { chainIds = ["1", "137", "8453"] } = params;
const results = [];
for (const chainId of chainIds) {
try {
const liquidity = await agent.getLiquidity(chainId);
results.push(liquidity);
await new Promise((resolve) => setTimeout(resolve, 300));
} catch (error) {
results.push({
chainId,
chainName: `Chain ${chainId}`,
error: error instanceof Error ? error.message : "Unknown error",
liquiditySources: []
});
}
}
return {
status: "success",
data: {
chains: results,
summary: {
totalChains: results.filter((r) => !r.error).length,
timestamp: Date.now()
}
}
};
}
};
// src/mcp/chain/get_chain_tools.ts
var GetSupportedChainsTool = {
name: "get_okx_supported_chains",
description: "Get all supported chains with their configuration details",
schema: {},
handler: async (agent, params) => {
const result = await agent.getChainInfo();
return {
status: "success",
data: result
};
}
};
var GetChainInfoTool = {
name: "get_okx_chain_info",
description: "Get detailed information for a specific chain",
schema: {
chainId: ChainInfoParamsSchema.shape.chainId
},
handler: async (agent, params) => {
const validatedParams = ChainInfoParamsSchema.required({ chainId: true }).parse(params);
const result = await agent.getChainInfo(validatedParams.chainId);
return {
status: "success",
data: result
};
}
};
// src/mcp/market/get_market_tools.ts
var GetMarketSummaryTool = {
name: "get_okx_market_summary",
description: "Get comprehensive market summary across OKX DEX supported chains",
schema: {},
handler: async (agent, params) => {
const result = await agent.getMarketSummary();
return {
status: "success",
data: result
};
}
};
var GetDEXOverviewTool = {
name: "get_okx_dex_overview",
description: "Get overview of OKX DEX aggregator capabilities and supported features",
schema: {},
handler: async (agent, params) => {
const supportedChainsList = Object.entries(SUPPORTED_CHAINS).map(([name, id]) => ({
name: name.replace(/_/g, " ").toLowerCase().replace(/\b\w/g, (l) => l.toUpperCase()),
chainId: id,
isEVM: !["501", "784", "607", "195"].includes(id)
// Non-EVM chains
}));
const result = {
platform: "OKX DEX Aggregator",
description: "Multi-chain DEX aggregator supporting both EVM and non-EVM chains",
features: [
"Multi-chain support across 28+ networks",
"Both EVM and non-EVM chain support",
"DEX aggregation for optimal pricing",
"Smart routing across multiple protocols",
"Real-time liquidity analysis",
"Cross-chain quote comparison",
"Low slippage optimization"
],
supportedChains: supportedChainsList,
totalSupportedChains: supportedChainsList.length,
evmChains: supportedChainsList.filter((c) => c.isEVM).length,
nonEvmChains: supportedChainsList.filter((c) => !c.isEVM).length,
keyMetrics: {
chainsSupported: supportedChainsList.length,
evmChains: supportedChainsList.filter((c) => c.isEVM).length,
nonEvmChains: supportedChainsList.filter((c) => !c.isEVM).length,
aggregatedDEXs: "100+",
averageSlippage: "< 1%"
},
apiCapabilities: [
"Token quotes and pricing",
"Multi-protocol routing",
"Liquidity source analysis",
"Chain information",
"Cross-chain comparisons"
],
timestamp: Date.now()
};
return {
status: "success",
data: result
};
}
};
// src/mcp/converter/symbol_converter_tool.ts
var import_zod2 = require("zod");
var SymbolConverterInstructionsSchema = import_zod2.z.object({
symbol: import_zod2.z.string().describe("Token symbol to convert (e.g., USDC, WETH, UNI)"),
chainId: import_zod2.z.string().describe("Chain ID to search on (e.g., '1' for Ethereum, '137' for Polygon)"),
useNoditSearch: import_zod2.z.boolean().optional().default(true).describe("Whether to use Nodit search API for comprehensive results")
});
var SymbolToAddressInstructionsTool = {
name: "get_symbol_to_address",
description: "Convert token symbols to contract addresses",
schema: {
symbol: SymbolConverterInstructionsSchema.shape.symbol,
chainId: SymbolConverterInstructionsSchema.shape.chainId,
useNoditSearch: SymbolConverterInstructionsSchema.shape.useNoditSearch
},
handler: async (agent, params) => {
const validatedParams = SymbolConverterInstructionsSchema.parse(params);
const { symbol, chainId, useNoditSearch } = validatedParams;
const chainIdToProtocol = {
"1": "ethereum",
"137": "polygon",
"42161": "arbitrum",
"8453": "base",
"10": "optimism",
"25": "ethereum",
// Cronos not directly supported, fallback to ethereum
"56": "ethereum",
// BSC not directly supported, fallback to ethereum
"43114": "ethereum"
// Avalanche not directly supported
};
const protocol = chainIdToProtocol[chainId] || "ethereum";
const network = "mainnet";
const instructions = {
status: "instruction",
message: `Converting symbol '${symbol}' to contract address on chain ${chainId}`,
symbol: symbol.toUpperCase(),
chainId,
protocol,
network,
// Multi-step approach
steps: [
{
step: 1,
method: "nodit_search",
enabled: useNoditSearch && !!chainIdToProtocol[chainId],
description: "Search using Nodit API for comprehensive token metadata",
action: {
tool: "nodit:call_nodit_api",
parameters: {
protocol,
network,
operationId: "searchTokenContractMetadataByKeyword",
requestBody: {
keyword: symbol.toUpperCase(),
page: 1,
rpp: 10,
withCount: true
}
}
},
expected_result: "List of token contracts with metadata including address, name, symbol, decimals",
scoring_criteria: [
"Exact symbol match gets highest priority",
"Verified/popular tokens preferred",
"Higher total supply often indicates main token",
"Consider deployment date (older = more established)"
]
},
{
step: 2,
method: "okx_quote_discovery",
description: "Use OKX quote API to discover token addresses through common pairs",
enabled: true,
action: {
tool: "get_okx_popular_token_pairs",
parameters: {
chainId
}
},
expected_result: "Popular token pairs that may contain the target token",
note: "Look for tokens in quote responses that match the symbol"
},
{
step: 3,
method: "cached_lookup",
description: "Check against known major token addresses",
enabled: true,
known_tokens: {
ethereum: {
USDC: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
USDT: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
WETH: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
WBTC: "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599",
DAI: "0x6b175474e89094c44da98b954eedeac495271d0f",
UNI: "0x1f9840a85d5af5bf1d1762f925bdaddc4201f984",
LINK: "0x514910771af9ca656af840dff83e8264ecf986ca"
},
polygon: {
USDC: "0x2791bca1f2de4661ed88a30c99a7a9449aa84174",
WPOL: "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270"
},
base: {
USDC: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
WETH: "0x4200000000000000000000000000000000000006"
},
arbitrum: {
USDC: "0xaf88d065e77c8cc2239327c5edb3a432268e5831",
WETH: "0x82af49447d8a07e3bd95bd0d56f35241523fbab1"
}
}
}
],
// Processing workflow
workflow: {
1: "If cached token exists, return immediately with high confidence",
2: useNoditSearch && chainIdToProtocol[chainId] ? "Execute Nodit search and filter results by exact symbol match" : "Skip Nodit search (chain not supported or disabled)",
3: "Execute OKX popular pairs discovery",
4: "Combine and rank results by confidence score",
5: "Return top candidate with metadata"
},
// Result format
expected_output: {
status: "success",
symbol: symbol.toUpperCase(),
chainId,
results: [
{
address: "0x...",
symbol: symbol.toUpperCase(),
name: "Token Name",
decimals: 18,
confidence: "high|medium|low",
source: "cached|nodit|okx_discovery",
verified: true,
metadata: {
totalSupply: "optional",
deployedAt: "optional",
logoUrl: "optional"
}
}
]
},
// Quick result for known tokens
quick_result: (() => {
const knownTokens = {
"1": {
// Ethereum
USDC: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
USDT: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
WETH: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
WBTC: "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599",
DAI: "0x6b175474e89094c44da98b954eedeac495271d0f"
},
"137": {
// Polygon
USDC: "0x2791bca1f2de4661ed88a30c99a7a9449aa84174",
WPOL: "0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270"
},
"8453": {
// Base
USDC: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
WETH: "0x4200000000000000000000000000000000000006"
}
};
const chainTokens = knownTokens[chainId];
const knownAddress = chainTokens?.[symbol.toUpperCase()];
if (knownAddress) {
return {
address: knownAddress,
symbol: symbol.toUpperCase(),
name: `${symbol.toUpperCase()} Token`,
decimals: symbol.toUpperCase() === "USDC" || symbol.toUpperCase() === "USDT" ? 6 : 18,
confidence: "high",
source: "cached_major_tokens",
verified: true
};
}
return null;
})(),
// Error handling
fallback_options: [
"Try searching with partial symbol matches",
"Check if token exists on different chains",
"Verify symbol spelling and try again",
"Use block explorer to manually find contract address"
],
timestamp: Date.now()
};
return {
status: "success",
data: instructions
};
}
};
// src/mcp/index.ts
var OKXDEXAnalyticsTools = {
// === QUOTE & PRICING (3 tools) ===
"GetQuoteTool": GetQuoteTool,
// Get swap quotes
"CompareMultiChainQuotesTool": CompareMultiChainQuotesTool,
// Cross-chain quote comparison
"GetPopularTokenPairsTool": GetPopularTokenPairsTool,
// Popular token pairs
// === LIQUIDITY ANALYTICS (2 tools) ===
"GetLiquidityTool": GetLiquidityTool,
// Chain liquidity info
"GetMultiChainLiquidityTool": GetMultiChainLiquidityTool,
// Multi-chain liquidity
// === CHAIN INFORMATION (2 tools) ===
"GetSupportedChainsTool": GetSupportedChainsTool,
// All supported chains
"GetChainInfoTool": GetChainInfoTool,
// Specific chain info
// === MARKET & OVERVIEW (2 tools) ===
"GetMarketSummaryTool": GetMarketSummaryTool,
// Market overview
"GetDEXOverviewTool": GetDEXOverviewTool,
// OKX DEX overview
// === SYMBOL CONVERTER (1 tool) ===
"SymbolToAddressInstructionsTool": SymbolToAddressInstructionsTool
// Symbol to address conversion instructions
};
var TOOL_COUNT = Object.keys(OKXDEXAnalyticsTools).length;
// src/index.ts
function createOKXDEXMcpServer(agent) {
const server = new import_mcp.McpServer({
name: "okx-dex-mcp",
version: "0.1.0"
});
for (const [toolKey, tool] of Object.entries(OKXDEXAnalyticsTools)) {
server.tool(tool.name, tool.description, tool.schema, async (params) => {
try {
const result = await tool.handler(agent, params);
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2)
}
]
};
} catch (error) {
console.error(`Tool execution error [${tool.name}]:`, error);
return {
isError: true,
content: [
{
type: "text",
text: error instanceof Error ? error.message : "Unknown error occurred"
}
]
};
}
});
}
console.error(`\u2705 Registered ${TOOL_COUNT} OKX DEX analytics tools`);
return server;
}
async function main() {
try {
console.error("\u{1F50D} Starting OKX DEX Analytics MCP Server...");
validateEnvironment();
const environment = getEnvironmentConfig();
const okxAgent = new OKXDEXAnalyticsAgent(environment);
const server = createOKXDEXMcpServer(okxAgent);
const transport = new import_stdio.StdioServerTransport();
await server.connect(transport);
console.error("\u2705 OKX DEX Analytics MCP Server is running!");
console.error("\u{1F527} Available capabilities:");
console.error(" \u2022 Multi-chain DEX aggregator analytics");
console.error(" \u2022 Token quotes & pricing across 20+ chains");
console.error(" \u2022 Liquidity analysis & protocol comparison");
console.error(" \u2022 Cross-chain quote optimization");
console.error(" \u2022 Token discovery & market data");
console.error(" \u2022 DEX protocol analytics");
console.error(" \u2022 Chain statistics & comparisons");
console.error(" \u2022 Market overview & insights");
console.error("\u{1F310} Supported chains:");
console.error(" \u2022 Ethereum, Polygon, Arbitrum, Base, Optimism");
console.error(" \u2022 Avalanche, BSC, Cronos, Fantom, zkSync Era");
console.error(" \u2022 And 15+ more EVM-compatible chains");
} catch (error) {
console.error("\u274C Error starting OKX DEX Analytics MCP server:", error);
process.exit(1);
}
}
main();