Skip to main content
Glama
symphony.ts16.2 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { z } from "zod"; import * as services from "../services/index.js"; import { type TransactionReceipt } from 'viem'; /** * Registers tools related to the Symphony DEX protocol. * @param server The MCP server instance */ export function registerSymphonyTools(server: McpServer) { // Get the current Symphony SDK configuration server.tool( "get_symphony_config", "Retrieves the current configuration of the Symphony SDK instance.", {}, async () => { try { const config = await services.getSymphonyConfig(); 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 Symphony config: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Update the Symphony SDK configuration server.tool( "set_symphony_config", "Updates the configuration of the shared Symphony SDK instance.", { options: z.object({ timeout: z.number().optional().describe("Timeout for RPC calls in milliseconds."), chainId: z.number().optional().describe("The ID of the blockchain network."), chainName: z.string().optional().describe("The name of the blockchain network."), rpcUrl: z.string().optional().describe("The URL for the RPC endpoint."), nativeAddress: z.string().optional().describe("The native token address."), wrappedNativeAddress: z.string().optional().describe("The wrapped native token address."), slippage: z.string().optional().describe("The slippage tolerance percentage."), publicClient: z.any().optional().describe("An instance of a public client."), tokens: z.record(z.any()).optional().describe("A list of supported tokens."), additionalTokens: z.record(z.any()).optional().describe("Additional tokens to be added."), overrideDefaultTokens: z.boolean().optional().describe("Whether to override the default token list."), feeParams: z.object({ paramFee: z.string().optional(), feeAddress: z.string().optional(), feeSharePercentage: z.string().optional(), }).optional().describe("Parameters for transaction fees."), }).optional() }, async ({ options }) => { try { await services.setSymphonyConfig(options || {}); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: "Symphony config updated successfully." }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error updating Symphony config: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Get list of available tokens on Symphony server.tool( "get_symphony_token_list", "Retrieves the list of all available tokens for swapping on the Symphony protocol.", { }, async () => { try { const tokenList = await services.getSymphonyTokenList(); return { content: [{ type: "text", text: JSON.stringify({ tokenList, network: 'Sei Mainnet' }, null, 2), }] }; } catch (error) { return { content: [{ type: "text", text: `Error fetching Symphony token list: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Check if a token is listed on Symphony server.tool( "is_symphony_token_listed", "Checks if a given token address is available for swaps in the Symphony protocol.", { tokenAddress: z.string().describe("The address of the token to check."), }, async ({ tokenAddress }) => { try { const isListed = await services.isSymphonyTokenListed(tokenAddress); return { content: [{ type: "text", text: JSON.stringify({ tokenAddress, isListed, network: 'Sei Mainnet' }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error checking if token is listed on Symphony: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Get Symphony Swap Route server.tool( "get_symphony_route", "Finds the best swap route for a given token pair using the Symphony protocol. Does not execute the swap.", { tokenInAddress: z.string().describe("The address of the input token. Use '0x0' for the native token (SEI)."), tokenOutAddress: z.string().describe("The address of the output token. Use '0x0' for the native token."), amount: z.string().describe("The amount of the input token to swap in human-readable units (e.g., '1.5')."), isRaw: z.boolean().optional().describe("If true, the input amount is treated as raw units (wei). Defaults to false."), }, async ({ tokenInAddress, tokenOutAddress, amount, isRaw = false }) => { try { const route = await services.getSymphonyRoute( tokenInAddress, tokenOutAddress, amount, { isRaw } ); const routeJson = JSON.stringify(route, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: `Route found. Expected output: ${route.amountOutFormatted}`, route: routeJson, network: 'Sei Mainnet' }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error getting Symphony route: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Execute Swap on Symphony server.tool( "swap_on_symphony", "Swaps one token for another using the Symphony protocol.", { tokenInAddress: z.string().describe("The address of the input token. Use '0x0' for the native token (SEI)."), tokenOutAddress: z.string().describe("The address of the output token. Use '0x0' for the native token."), amount: z.string().describe("The amount of the input token to swap in human-readable units (e.g., '1.5')."), isRaw: z.boolean().optional().describe("If true, the input amount is treated as raw units (wei). Defaults to false."), }, async ({ tokenInAddress, tokenOutAddress, amount, isRaw = false }) => { try { const swapReceipt: TransactionReceipt = await services.swapOnSymphony( tokenInAddress, tokenOutAddress, amount, { isRaw } ); return { content: [{ type: "text", text: JSON.stringify({ success: true, transactionHash: swapReceipt.transactionHash, blockNumber: swapReceipt.blockNumber.toString(), gasUsed: swapReceipt.gasUsed.toString(), status: swapReceipt.status, network: 'Sei Mainnet' }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error executing swap on Symphony: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Execute Swap on Symphony with Advanced Parameters server.tool( "swap_on_symphony_advanced", "Swaps one token for another using the Symphony protocol, with optional parameters for routing and execution.", { tokenInAddress: z.string().describe("The address of the input token. Use '0x0' for the native token."), tokenOutAddress: z.string().describe("The address of the output token. Use '0x0' for the native token."), amount: z.string().describe("The amount of the input token to swap."), params: z.object({ routeOptions: z.record(z.any()).optional().describe("A JSON object of options for the routing engine."), swapOptions: z.record(z.any()).optional().describe("A JSON object of options for the swap execution."), slippage: z.record(z.any()).optional().describe("A JSON object of slippage settings for the swap.") }).optional().describe("Optional parameters for routing, execution, and slippage.") }, async ({ tokenInAddress, tokenOutAddress, amount, params = {} }) => { try { const result = await services.swapOnSymphonyAdvanced( tokenInAddress, tokenOutAddress, amount, { routeOptions: params.routeOptions, swapOptions: params.swapOptions, slippage: params.slippage ? { slippageAmount: params.slippage.slippageAmount, isRaw: params.slippage.isRaw || false, isBps: params.slippage.isBps || false, outTokenDecimals: params.slippage.outTokenDecimals } : undefined } ); const response: Record<string, any> = { success: true, swapTransactionHash: result.swapReceipt.transactionHash, status: result.swapReceipt.status, blockNumber: result.swapReceipt.blockNumber.toString(), } if (result.approveReceipt) { response.approveTransactionHash = result.approveReceipt.transactionHash; } return { content: [{ type: "text", text: JSON.stringify(response, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error executing swap on Symphony: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Get Total Amount Out from Route server.tool( "get_symphony_total_amount_out", "Calculates the total output amount for a given route.", { tokenInAddress: z.string().describe("The address of the input token."), tokenOutAddress: z.string().describe("The address of the output token."), amount: z.string().describe("The amount of the input token for the swap."), options: z.record(z.any()).optional().describe("A JSON object of options for the routing engine.") }, async ({ tokenInAddress, tokenOutAddress, amount, options = {} }) => { try { const totalAmountOut = await services.getSymphonyTotalAmountOut( tokenInAddress, tokenOutAddress, amount, options ); const amountOutJson = JSON.stringify(totalAmountOut, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2); return { content: [{ type: "text", text: amountOutJson }] }; } catch (error) { return { content: [{ type: "text", text: `Error calculating total amount out from route: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Check Symphony Token Approval Status server.tool( "check_symphony_approval", "Checks if the Symphony protocol has sufficient allowance to spend a specific token for a swap.", { tokenInAddress: z.string().describe("The address of the input token to check."), tokenOutAddress: z.string().describe("The address of the output token (needed to determine the route)."), amount: z.string().describe("The amount of the input token for the potential swap."), options: z.record(z.any()).optional().describe("A JSON object of options for the routing engine.") }, async ({ tokenInAddress, tokenOutAddress, amount, options = {} }) => { try { const isApproved = await services.checkSymphonyApproval( tokenInAddress, tokenOutAddress, amount, options ); return { content: [{ type: "text", text: JSON.stringify({ success: true, isApproved: isApproved, message: isApproved ? "Sufficient allowance exists." : "Allowance is insufficient. Please approve the token first." }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error checking Symphony approval: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Approve Symphony Token for Swapping server.tool( "approve_symphony_token", "Approves the Symphony protocol to spend a specific token for swapping. This is a necessary step before swapping non-native tokens.", { tokenInAddress: z.string().describe("The address of the input token to approve."), tokenOutAddress: z.string().describe("The address of the output token (needed to determine the correct contract to approve)."), amount: z.string().describe("The amount of the input token to approve for spending."), options: z.record(z.any()).optional().describe("A JSON object of options for the routing engine.") }, async ({ tokenInAddress, tokenOutAddress, amount, options }) => { try { const approvalReceipt = await services.approveSymphonyToken( tokenInAddress, tokenOutAddress, amount, options ); return { content: [{ type: "text", text: JSON.stringify({ success: true, message: "Approval successful.", transactionHash: approvalReceipt.transactionHash, status: approvalReceipt.status, blockNumber: approvalReceipt.blockNumber.toString() }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error giving approval to Symphony: ${error instanceof Error ? error.message : String(error)}` }], isError: true }; } } ); // Generate Symphony Swap Calldata server.tool( "generate_symphony_swap_calldata", "Generates the transaction calldata for a swap without executing it.", { tokenInAddress: z.string().describe("The address of the input token."), tokenOutAddress: z.string().describe("The address of the output token."), amount: z.string().describe("The amount of the input token to swap."), options: z.record(z.any()).optional().describe("A JSON object of options for the routing engine."), params: z.record(z.any()).optional().describe("A JSON object of slippage settings.") }, async ({ tokenInAddress, tokenOutAddress, amount, options, params }) => { try { const txData = await services.generateSymphonySwapCalldata( tokenInAddress, tokenOutAddress, amount, options, params ); return { content: [{ type: "text", text: JSON.stringify(txData, (key, value) => typeof value === 'bigint' ? value.toString() : value, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `Error generating Symphony calldata: ${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