UNPKG

@venly/wallet-mcp

Version:

Production-ready MCP server enabling AI agents to perform Web3 wallet operations through Venly's blockchain infrastructure. Supports 14+ networks including Ethereum, Polygon, Arbitrum, and stablecoin operations.

1,127 lines 139 kB
/** * Venly MCP Server * * Main MCP server implementation that provides blockchain wallet operations * through the Model Context Protocol */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js'; import { VenlyClient } from '../venly/VenlyClient.js'; import { CredentialValidator } from '../auth/CredentialValidator.js'; import winston, { format, transports } from 'winston'; import dotenv from 'dotenv'; // Load environment variables dotenv.config(); /** * Main Venly MCP Server class */ export class VenlyMCPServer { server; venlyClient; logger; tools = new Map(); environment; constructor(environment) { this.environment = environment; this.logger = this.createLogger(); this.server = new Server({ name: `venly-mcp-server-${environment}`, version: '1.0.0', }, { capabilities: { tools: {}, }, }); // Initialize Venly client this.venlyClient = new VenlyClient(environment); // Register tools and handlers this.registerTools(); this.setupHandlers(); this.logger.info('VenlyMCPServer initialized', { environment }); } // ============================================================================ // Tool Registration // ============================================================================ /** * Register all available MCP tools */ registerTools() { // Base credential schema for all tools const baseCredentialProperties = { venly_client_id: { type: 'string', description: 'Your Venly Client ID from the Developer Portal' }, venly_client_secret: { type: 'string', description: 'Your Venly Client Secret from the Developer Portal' } }; // Wallet Management Tools this.registerTool({ name: 'create_wallet', description: 'Create a new blockchain wallet with specified network and configuration', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, secretType: { type: 'string', enum: ['ETHEREUM', 'MATIC', 'BSC', 'ARBITRUM', 'AVAX', 'BITCOIN', 'LITECOIN', 'OPTIMISM', 'BASE'], description: 'Blockchain network for the wallet' }, walletType: { type: 'string', enum: ['WHITE_LABEL', 'APPLICATION', 'IMPORTED'], description: 'Type of wallet to create' }, identifier: { type: 'string', description: 'Optional identifier for the wallet (e.g., user email)' }, description: { type: 'string', description: 'Optional description for the wallet' }, pincode: { type: 'string', description: 'Optional PIN code for wallet security (4-20 characters)' } }, required: ['venly_client_id', 'venly_client_secret', 'secretType', 'walletType'] } }); this.registerTool({ name: 'delete_user', description: 'Delete a user and all associated data (use with caution)', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, userId: { type: 'string', description: 'Unique identifier of the user to delete' } }, required: ['venly_client_id', 'venly_client_secret', 'userId'] } }); this.registerTool({ name: 'list_users', description: 'List all users with pagination and optional filtering', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, page: { type: 'number', description: 'Page number for pagination (default: 0)' }, size: { type: 'number', description: 'Number of users per page (default: 20, max: 100)' }, reference: { type: 'string', description: 'Filter by user reference' }, includeSigningMethods: { type: 'boolean', description: 'Include signing method details (default: false)' } }, required: ['venly_client_id', 'venly_client_secret'] } }); this.registerTool({ name: 'manage_signing_methods', description: 'Add or manage signing methods for a user (PIN, Emergency Code, Biometric)', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, userId: { type: 'string', description: 'Unique identifier of the user' }, action: { type: 'string', enum: ['CREATE', 'LIST'], description: 'Action to perform: CREATE new signing method or LIST existing ones' }, signingMethod: { type: 'object', properties: { type: { type: 'string', enum: ['PIN', 'EMERGENCY_CODE', 'BIOMETRIC'], description: 'Type of signing method to create' }, value: { type: 'string', description: 'PIN (6 digits) or Emergency Code (25 chars, leave empty for auto-generation)' } }, description: 'Signing method details (required for CREATE action)' } }, required: ['venly_client_id', 'venly_client_secret', 'userId', 'action'] } }); this.registerTool({ name: 'get_token_balances', description: 'Get all token balances for a wallet with optional enriched metadata including USD prices, portfolio percentages, and token categories', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, walletId: { type: 'string', description: 'Unique identifier of the wallet' }, enriched: { type: 'boolean', description: 'Whether to include enriched metadata (thumbnails, USD prices, portfolio percentages, categories). Default: false' } }, required: ['venly_client_id', 'venly_client_secret', 'walletId'] } }); this.registerTool({ name: 'get_token_portfolio', description: 'Get comprehensive token portfolio analysis including total USD value, category breakdown, and performance metrics', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, walletId: { type: 'string', description: 'Unique identifier of the wallet' } }, required: ['venly_client_id', 'venly_client_secret', 'walletId'] } }); // Transaction Tools this.registerTool({ name: 'send_transaction', description: 'Send native tokens from one wallet to another', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, walletId: { type: 'string', description: 'Unique identifier of the source wallet' }, to: { type: 'string', description: 'Destination wallet address (0x...)' }, value: { type: 'number', description: 'Amount to send in wei (for native tokens like ETH, MATIC)' }, secretType: { type: 'string', enum: ['ETHEREUM', 'MATIC', 'BSC', 'ARBITRUM', 'AVAX', 'OPTIMISM', 'BASE'], description: 'Blockchain network for the transaction' }, pincode: { type: 'string', description: 'PIN code for wallet authentication (optional, defaults to 123456 for testing)' } }, required: ['venly_client_id', 'venly_client_secret', 'walletId', 'to', 'value', 'secretType'] } }); this.registerTool({ name: 'send_token', description: 'Send ERC-20 tokens from one wallet to another', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, walletId: { type: 'string', description: 'Unique identifier of the source wallet' }, to: { type: 'string', description: 'Destination wallet address (0x...)' }, tokenAddress: { type: 'string', description: 'Contract address of the ERC-20 token (0x...)' }, value: { type: 'number', description: 'Amount to send in token\'s smallest unit (e.g., for USDC with 6 decimals, 1000000 = 1 USDC)' }, secretType: { type: 'string', enum: ['ETHEREUM', 'MATIC', 'BSC', 'ARBITRUM', 'AVAX', 'OPTIMISM', 'BASE'], description: 'Blockchain network for the transaction' }, pincode: { type: 'string', description: 'PIN code for wallet authentication (optional, defaults to 123456 for testing)' } }, required: ['venly_client_id', 'venly_client_secret', 'walletId', 'to', 'tokenAddress', 'value', 'secretType'] } }); this.registerTool({ name: 'get_transaction', description: 'Get details of a specific transaction by hash', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, transactionHash: { type: 'string', description: 'Transaction hash to look up (0x...)' }, secretType: { type: 'string', enum: ['ETHEREUM', 'MATIC', 'BSC', 'ARBITRUM', 'AVAX', 'OPTIMISM', 'BASE'], description: 'Blockchain network where the transaction occurred' } }, required: ['venly_client_id', 'venly_client_secret', 'transactionHash', 'secretType'] } }); // User Management Tools this.registerTool({ name: 'create_user', description: 'Create a new user with optional signing method for wallet management', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, reference: { type: 'string', description: 'Optional reference identifier for the user (e.g., email, user ID from your system)' }, signingMethod: { type: 'object', properties: { type: { type: 'string', enum: ['PIN', 'EMERGENCY_CODE', 'BIOMETRIC'], description: 'Type of signing method to create' }, value: { type: 'string', description: 'PIN (6 digits) or Emergency Code (25 chars, leave empty for auto-generation)' } }, description: 'Optional signing method to create with the user' } }, required: ['venly_client_id', 'venly_client_secret'] } }); this.registerTool({ name: 'get_user', description: 'Get user details including signing methods and profile information', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, userId: { type: 'string', description: 'Unique identifier of the user' } }, required: ['venly_client_id', 'venly_client_secret', 'userId'] } }); this.registerTool({ name: 'update_user', description: 'Update user profile information and reference', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, userId: { type: 'string', description: 'Unique identifier of the user' }, reference: { type: 'string', description: 'New reference identifier for the user' } }, required: ['venly_client_id', 'venly_client_secret', 'userId'] } }); // Fiat Bridge Tools this.registerTool({ name: 'get_exchange_rates', description: 'Get real-time fiat/crypto conversion rates from multiple providers', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, fromCurrency: { type: 'string', description: 'Source currency code (USD, EUR, ETH, BTC, USDC)' }, toCurrency: { type: 'string', description: 'Target currency code (USD, EUR, ETH, BTC, USDC)' }, provider: { type: 'string', enum: ['TRANSAK', 'MOONPAY', 'RAMP_NETWORK'], description: 'Optional provider filter for rates' } }, required: ['venly_client_id', 'venly_client_secret', 'fromCurrency', 'toCurrency'] } }); // Webhook System Tools this.registerTool({ name: 'setup_transaction_webhooks', description: 'Configure real-time transaction monitoring webhooks', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, walletId: { type: 'string', description: 'Wallet ID to monitor (optional, will auto-detect if not provided)' }, secretType: { type: 'string', enum: ['ETHEREUM', 'MATIC', 'BSC', 'ARBITRUM', 'AVAX', 'OPTIMISM', 'BASE'], description: 'Blockchain network to monitor' }, webhookUrl: { type: 'string', description: 'URL endpoint to receive webhook notifications' }, events: { type: 'array', items: { type: 'string', enum: ['TRANSACTION_PENDING', 'TRANSACTION_CONFIRMED', 'TRANSACTION_FAILED', 'TRANSACTION_DROPPED'] }, description: 'Transaction events to monitor' }, description: { type: 'string', description: 'Optional description for the webhook' }, authType: { type: 'string', enum: ['NONE', 'API_KEY', 'BASIC_AUTH'], description: 'Authentication type for webhook endpoint' }, authValue: { type: 'string', description: 'Authentication value (API key or basic auth credentials)' } }, required: ['venly_client_id', 'venly_client_secret', 'webhookUrl', 'events'] } }); this.registerTool({ name: 'setup_balance_webhooks', description: 'Configure balance change notification webhooks', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, walletId: { type: 'string', description: 'Wallet ID to monitor (optional, will auto-detect if not provided)' }, secretType: { type: 'string', enum: ['ETHEREUM', 'MATIC', 'BSC', 'ARBITRUM', 'AVAX', 'OPTIMISM', 'BASE'], description: 'Blockchain network to monitor' }, webhookUrl: { type: 'string', description: 'URL endpoint to receive webhook notifications' }, minBalanceChange: { type: 'number', description: 'Minimum balance change to trigger notification' }, percentageChange: { type: 'number', description: 'Percentage change threshold to trigger notification' }, description: { type: 'string', description: 'Optional description for the webhook' }, authType: { type: 'string', enum: ['NONE', 'API_KEY', 'BASIC_AUTH'], description: 'Authentication type for webhook endpoint' }, authValue: { type: 'string', description: 'Authentication value (API key or basic auth credentials)' } }, required: ['venly_client_id', 'venly_client_secret', 'webhookUrl'] } }); this.registerTool({ name: 'setup_portfolio_webhooks', description: 'Configure portfolio value change alert webhooks', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, walletId: { type: 'string', description: 'Wallet ID to monitor (optional, will auto-detect if not provided)' }, webhookUrl: { type: 'string', description: 'URL endpoint to receive webhook notifications' }, minValueChange: { type: 'number', description: 'Minimum USD value change to trigger notification' }, percentageChange: { type: 'number', description: 'Portfolio percentage change threshold to trigger notification' }, description: { type: 'string', description: 'Optional description for the webhook' }, authType: { type: 'string', enum: ['NONE', 'API_KEY', 'BASIC_AUTH'], description: 'Authentication type for webhook endpoint' }, authValue: { type: 'string', description: 'Authentication value (API key or basic auth credentials)' } }, required: ['venly_client_id', 'venly_client_secret', 'webhookUrl'] } }); this.registerTool({ name: 'process_webhook_events', description: 'Process and analyze incoming webhook events', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, eventPayload: { type: 'object', description: 'Raw webhook event payload to process' }, eventType: { type: 'string', description: 'Type of webhook event (optional, will be extracted from payload)' }, validateSignature: { type: 'boolean', description: 'Whether to validate webhook signature (default: false)' } }, required: ['venly_client_id', 'venly_client_secret', 'eventPayload'] } }); this.registerTool({ name: 'get_webhook_status', description: 'Monitor webhook health and delivery status', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, webhookId: { type: 'string', description: 'Specific webhook ID to check status for' }, webhookUrl: { type: 'string', description: 'Webhook URL to check status for' } }, required: ['venly_client_id', 'venly_client_secret'] } }); this.registerTool({ name: 'create_fiat_onramp', description: 'Generate fiat-to-crypto purchase links using Transak, MoonPay, or Ramp Network', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, walletId: { type: 'string', description: 'Target wallet ID for crypto deposit' }, provider: { type: 'string', enum: ['TRANSAK', 'MOONPAY', 'RAMP_NETWORK'], description: 'Fiat onramp provider' }, fiatAmount: { type: 'number', description: 'Amount in fiat currency (e.g., 100 for $100)' }, fiatCurrency: { type: 'string', description: 'Fiat currency code (USD, EUR, GBP)' }, cryptoCurrency: { type: 'string', description: 'Target crypto currency (ETH, USDC, BTC)' }, cryptoNetwork: { type: 'string', description: 'Blockchain network (ETHEREUM, MATIC, BSC)' }, email: { type: 'string', description: 'User email for onramp process' }, returnUrl: { type: 'string', description: 'Return URL after completion' }, selectedCountryCode: { type: 'string', description: 'Country code (US, GB, DE)' } }, required: ['venly_client_id', 'venly_client_secret', 'walletId', 'provider'] } }); this.registerTool({ name: 'create_fiat_offramp', description: 'Generate crypto-to-fiat withdrawal links using Transak, MoonPay, or Ramp Network', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, walletId: { type: 'string', description: 'Source wallet ID for crypto withdrawal' }, provider: { type: 'string', enum: ['TRANSAK', 'MOONPAY', 'RAMP_NETWORK'], description: 'Fiat offramp provider' }, cryptoAmount: { type: 'number', description: 'Amount in crypto currency (e.g., 1000000 for 1 USDC with 6 decimals)' }, cryptoCurrency: { type: 'string', description: 'Source crypto currency (ETH, USDC, BTC)' }, cryptoNetwork: { type: 'string', description: 'Blockchain network (ETHEREUM, MATIC, BSC)' }, fiatCurrency: { type: 'string', description: 'Target fiat currency (USD, EUR, GBP)' }, email: { type: 'string', description: 'User email for offramp process' }, returnUrl: { type: 'string', description: 'Return URL after completion' }, selectedCountryCode: { type: 'string', description: 'Country code (US, GB, DE)' } }, required: ['venly_client_id', 'venly_client_secret', 'walletId', 'provider'] } }); this.registerTool({ name: 'track_fiat_transaction', description: 'Monitor fiat conversion transaction status by provider transaction ID', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, transactionId: { type: 'string', description: 'Provider transaction ID to track' }, provider: { type: 'string', enum: ['TRANSAK', 'MOONPAY', 'RAMP_NETWORK'], description: 'Fiat provider that issued the transaction' } }, required: ['venly_client_id', 'venly_client_secret', 'transactionId', 'provider'] } }); // Workflow Tools this.registerTool({ name: 'create_workflow_template', description: 'Define reusable multi-step financial workflows', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, name: { type: 'string' }, description: { type: 'string' }, category: { type: 'string', enum: ['PAYMENT', 'NFT_DISTRIBUTION', 'TOKEN_MANAGEMENT', 'PORTFOLIO_REBALANCING', 'CUSTOM'] }, steps: { type: 'array', items: { type: 'object', properties: { id: { type: 'string' }, name: { type: 'string' }, type: { type: 'string', enum: ['CREATE_WALLET', 'SEND_TRANSACTION', 'SEND_TOKEN', 'CHECK_BALANCE', 'WAIT_FOR_CONFIRMATION', 'FIAT_ONRAMP', 'DELAY'] }, parameters: { type: 'object' }, dependencies: { type: 'array', items: { type: 'string' } } }, required: ['id', 'name', 'type', 'parameters'] } }, parameters: { type: 'array', items: { type: 'object', properties: { name: { type: 'string' }, type: { type: 'string', enum: ['string', 'number', 'boolean', 'address', 'amount'] }, required: { type: 'boolean' }, defaultValue: {}, description: { type: 'string' } }, required: ['name', 'type', 'required'] } } }, required: ['venly_client_id', 'venly_client_secret', 'name', 'description', 'category', 'steps'] } }); this.registerTool({ name: 'execute_workflow', description: 'Execute workflows with real-time monitoring', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, templateId: { type: 'string' }, parameters: { type: 'object' }, dryRun: { type: 'boolean' }, stopOnError: { type: 'boolean' }, maxRetries: { type: 'number' }, delayBetweenSteps: { type: 'number' } }, required: ['venly_client_id', 'venly_client_secret', 'parameters'] } }); this.registerTool({ name: 'monitor_workflow_status', description: 'Track workflow execution progress', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, workflowExecutionId: { type: 'string' }, templateId: { type: 'string' }, includeStepDetails: { type: 'boolean' }, includeLogs: { type: 'boolean' } }, required: ['venly_client_id', 'venly_client_secret', 'workflowExecutionId'] } }); // Financial Data Tools this.registerTool({ name: 'export_financial_data', description: 'Generate standardized reports for tax/accounting', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, walletIds: { type: 'array', items: { type: 'string' } }, userId: { type: 'string' }, startDate: { type: 'string' }, endDate: { type: 'string' }, reportType: { type: 'string', enum: ['TAX_REPORT', 'ACCOUNTING_EXPORT', 'PORTFOLIO_SUMMARY', 'TRANSACTION_HISTORY', 'GAINS_LOSSES'] }, format: { type: 'string', enum: ['CSV', 'JSON', 'PDF', 'XLSX'] }, currency: { type: 'string', enum: ['USD', 'EUR', 'GBP'] }, taxYear: { type: 'number' }, jurisdiction: { type: 'string' }, includeMetadata: { type: 'boolean' }, includeNFTs: { type: 'boolean' }, includeStaking: { type: 'boolean' }, includeFees: { type: 'boolean' } }, required: ['venly_client_id', 'venly_client_secret', 'reportType', 'format'] } }); this.registerTool({ name: 'optimize_transaction_routing', description: 'Intelligent routing across chains with cost optimization', inputSchema: { type: 'object', properties: { ...baseCredentialProperties, fromTokenSymbol: { type: 'string' }, fromTokenAddress: { type: 'string' }, fromTokenAmount: { type: 'number' }, fromTokenDecimals: { type: 'number' }, toTokenSymbol: { type: 'string' }, toTokenAddress: { type: 'string' }, targetAmount: { type: 'number' }, fromNetwork: { type: 'string', enum: ['ETHEREUM', 'MATIC', 'BSC', 'ARBITRUM', 'OPTIMISM', 'AVALANCHE'] }, toNetwork: { type: 'string', enum: ['ETHEREUM', 'MATIC', 'BSC', 'ARBITRUM', 'OPTIMISM', 'AVALANCHE'] }, fromWalletId: { type: 'string' }, toWalletId: { type: 'string' }, slippageTolerance: { type: 'number' }, maxHops: { type: 'number' }, prioritizeSpeed: { type: 'boolean' }, prioritizeCost: { type: 'boolean' }, prioritizeSecurity: { type: 'boolean' }, excludeDEXs: { type: 'array', items: { type: 'string' } }, preferredDEXs: { type: 'array', items: { type: 'string' } }, deadline: { type: 'number' }, enableMEVProtection: { type: 'boolean' } }, required: ['venly_client_id', 'venly_client_secret', 'fromTokenSymbol', 'fromTokenAmount', 'toTokenSymbol', 'fromNetwork', 'toNetwork', 'fromWalletId'] } }); this.logger.info(`Registered ${this.tools.size} MCP tools`); } /** * Register a single MCP tool */ registerTool(tool) { this.tools.set(tool.name, tool); this.logger.debug(`Registered tool: ${tool.name}`); } // ============================================================================ // MCP Handlers Setup // ============================================================================ /** * Setup MCP request handlers */ setupHandlers() { this.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: Array.from(this.tools.values()) })); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { this.logger.info(`🚀 Calling MCP tool handler: ${name}`); const result = await this.handleToolCall(name, args || {}); this.logger.info(`✅ MCP tool ${name} completed successfully`); return result; } catch (error) { this.logger.error(`❌ MCP tool error: ${name}`, { error: error instanceof Error ? error.message : error, requestData: { hasClientId: !!args?.['venly_client_id'], hasClientSecret: !!args?.['venly_client_secret'], toolName: name }, stack: error instanceof Error ? error.stack : undefined }); throw new McpError(ErrorCode.InternalError, `Tool execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`); } }); } // ============================================================================ // Tool Implementation // ============================================================================ /** * Handle individual tool calls */ async handleToolCall(toolName, args) { switch (toolName) { // Wallet Management Tools case 'create_wallet': return this.handleCreateWallet(args); case 'list_wallets': return this.handleListWallets(args); case 'get_wallet_info': return this.handleGetWalletInfo(args); case 'get_wallet_balance': return this.handleGetWalletBalance(args); case 'get_token_balances': return this.handleGetTokenBalances(args); case 'get_token_portfolio': return this.handleGetTokenPortfolio(args); // Transaction Tools case 'send_transaction': return this.handleSendTransaction(args); case 'send_token': return this.handleSendToken(args); case 'get_transaction': return this.handleGetTransaction(args); // User Management Tools case 'create_user': return this.handleCreateUser(args); case 'get_user': return this.handleGetUser(args); case 'update_user': return this.handleUpdateUser(args); case 'delete_user': return this.handleDeleteUser(args); case 'list_users': return this.handleListUsers(args); case 'manage_signing_methods': return this.handleManageSigningMethods(args); // Fiat Bridge Tools case 'get_exchange_rates': return this.handleGetExchangeRates(args); case 'create_fiat_onramp': return this.handleCreateFiatOnramp(args); case 'create_fiat_offramp': return this.handleCreateFiatOfframp(args); case 'track_fiat_transaction': return this.handleTrackFiatTransaction(args); // Webhook System Tools case 'setup_transaction_webhooks': return this.handleSetupTransactionWebhooks(args); case 'setup_balance_webhooks': return this.handleSetupBalanceWebhooks(args); case 'setup_portfolio_webhooks': return this.handleSetupPortfolioWebhooks(args); case 'process_webhook_events': return this.handleProcessWebhookEvents(args); case 'get_webhook_status': return this.handleGetWebhookStatus(args); // Workflow Tools case 'create_workflow_template': return this.handleCreateWorkflowTemplate(args); case 'execute_workflow': return this.handleExecuteWorkflow(args); case 'monitor_workflow_status': return this.handleMonitorWorkflowStatus(args); // Financial Data Tools case 'export_financial_data': return this.handleExportFinancialData(args); case 'optimize_transaction_routing': return this.handleOptimizeTransactionRouting(args); default: throw new Error(`Unknown tool: ${toolName}`); } } /** * Handle create_wallet tool */ async handleCreateWallet(args) { try { const credentials = CredentialValidator.extractCredentials(args); CredentialValidator.validateCredentials(credentials); const createWalletParams = { secretType: args['secretType'], walletType: args['walletType'], identifier: args['identifier'], description: args['description'], pincode: args['pincode'] }; if (!createWalletParams.secretType || !createWalletParams.walletType) { throw new Error('secretType and walletType are required'); } const wallet = await this.venlyClient.createWallet(credentials, createWalletParams); if (!wallet) { throw new Error('Failed to create wallet'); } return { content: [{ type: 'text', text: JSON.stringify({ success: true, wallet: { id: wallet.id, address: wallet.address, secretType: wallet.secretType, walletType: wallet.walletType, identifier: wallet.identifier, description: wallet.description, balance: wallet.balance }, debug: { environment: this.environment, timestamp: new Date().toISOString(), toolName: 'create_wallet' } }, null, 2) }] }; } catch (error) { return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error', errorType: error?.constructor?.name || 'UnknownError', debug: { environment: this.environment, timestamp: new Date().toISOString(), toolName: 'create_wallet' } }, null, 2) }] }; } } /** * Handle list_wallets tool */ async handleListWallets(args) { try { const credentials = CredentialValidator.extractCredentials(args); CredentialValidator.validateCredentials(credentials); const paginationParams = {}; if (args['page'] !== undefined) paginationParams.page = args['page']; if (args['size'] !== undefined) paginationParams.size = args['size']; const wallets = await this.venlyClient.listWallets(credentials, paginationParams); if (!wallets) { throw new Error('Failed to retrieve wallets'); } return { content: [{ type: 'text', text: JSON.stringify({ success: true, wallets: wallets.map(wallet => ({ id: wallet.id, address: wallet.address, secretType: wallet.secretType, walletType: wallet.walletType, identifier: wallet.identifier, description: wallet.description, balance: wallet.balance })), count: wallets.length, debug: { environment: this.environment, timestamp: new Date().toISOString(), credentialsUsed: { clientId: credentials.clientId ? credentials.clientId.substring(0, 8) + '...' : 'unknown', serverEnvironment: this.environment } } }, null, 2) }] }; } catch (error) { return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error', errorType: error?.constructor?.name || 'UnknownError', debug: { environment: this.environment, timestamp: new Date().toISOString(), toolName: 'list_wallets' } }, null, 2) }] }; } } /** * Handle get_wallet_info tool with auto wallet ID detection */ async handleGetWalletInfo(args) { try { const credentials = CredentialValidator.extractCredentials(args); CredentialValidator.validateCredentials(credentials); let walletId = args['walletId']; // If no walletId provided or it's a test ID, get a real one from list_wallets if (!walletId || walletId.startsWith('test-')) { console.log('🔍 No valid walletId provided, fetching real wallet from list_wallets...'); const wallets = await this.venlyClient.listWallets(credentials, { page: 1, size: 1 }); if (wallets.length === 0) { throw new Error('No wallets found. Please create a wallet first using create_wallet, then use the returned wallet ID directly in subsequent calls.'); } const firstWallet = wallets[0]; if (!firstWallet) { throw new Error('Invalid wallet data received from list_wallets'); } walletId = firstWallet.id; console.log(`✅ Using real wallet ID: ${walletId}`); } const result = await this.venlyClient.getWallet(credentials, walletId); if (!result) { throw new Error('Wallet not found'); } return { content: [{ type: 'text', text: JSON.stringify({ success: true, wallet: { id: result.id, address: result.address, secretType: result.secretType, walletType: result.walletType, identifier: result.identifier, description: result.description, balance: result.balance, primary: result.primary, hasCustomPin: result.hasCustomPin, archived: result.archived, createdAt: result.createdAt }, debug: { environment: this.environment, timestamp: new Date().toISOString(), toolName: 'get_wallet_info', autoDetectedWalletId: walletId !== args['walletId'] } }, null, 2) }] }; } catch (error) { return { content: [{ type: 'text', text: JSON.stringify({ success: false, error: error instanceof Error ? error.message : 'Unknown error', errorType: error?.constructor?.name || 'UnknownError', debug: { environment: this.environment, timestamp: new Date().toISOString(), toolName: 'get_wallet_info' } }, null, 2) }] }; } } /** * Handle get_wallet_balance tool w