UNPKG

0xgasless-mcp

Version:

MCP server for 0xGasless smart accounts with gasless blockchain operations. Directly connects to Claude Desktop

333 lines 12.5 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.main = main; const agentkit_1 = require("@0xgasless/agentkit"); const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js"); const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js"); const types_js_1 = require("@modelcontextprotocol/sdk/types.js"); const dotenv = __importStar(require("dotenv")); const version_js_1 = require("./version.js"); const stream_1 = require("stream"); // Load environment variables dotenv.config(); // Global state for agentkit let agentkitInstance = null; let agentkitActions = []; let toolsInitialized = false; // Create a null stream to suppress stdout during operations const nullStream = new stream_1.Writable({ write(chunk, encoding, callback) { callback(); } }); // Function to suppress stdout during execution function withSuppressedStdout(fn) { const originalStdout = process.stdout.write; const originalConsoleLog = console.log; // Redirect stdout and console.log to null during execution process.stdout.write = nullStream.write.bind(nullStream); console.log = () => { }; // Completely silence console.log return fn().finally(() => { // Restore original stdout and console.log process.stdout.write = originalStdout; console.log = originalConsoleLog; }); } // Initialize agentkit and get actions async function initializeAgentkit() { if (toolsInitialized && agentkitInstance) { return { agentkit: agentkitInstance, actions: agentkitActions }; } try { console.error("🚀 Initializing 0xGasless Agentkit..."); const privateKey = process.env.PRIVATE_KEY; const rpcUrl = process.env.RPC_URL; const apiKey = process.env.API_KEY; const chainID = Number(process.env.CHAIN_ID) || 56; console.error(`📋 Config: Chain ${chainID}`); // Configure agentkit with wallet - suppress any stdout output const agentkit = await withSuppressedStdout(async () => { return await agentkit_1.Agentkit.configureWithWallet({ privateKey, rpcUrl, apiKey, chainID, }); }); console.error("✅ Agentkit configured successfully"); // Get all available actions from the agentkit const actions = (0, agentkit_1.getAllAgentkitActions)(); console.error(`📦 Found ${actions.length} agentkit actions`); agentkitInstance = agentkit; agentkitActions = actions; toolsInitialized = true; return { agentkit, actions }; } catch (error) { console.error("❌ Failed to initialize Agentkit:", error); throw error; } } // Tool name mapping between MCP and AgentKit const MCP_TO_AGENTKIT_MAPPING = { 'get-address': 'get_address', 'get-balance': 'get_balance', 'transfer-token': 'smart_transfer', 'swap-tokens': 'smart_swap', }; // Convert MCP arguments to AgentKit arguments function convertMcpArgsToAgentkitArgs(mcpToolName, mcpArgs) { switch (mcpToolName) { case 'get-address': return {}; case 'get-balance': if (mcpArgs.address === '0x0000000000000000000000000000000000000000') { return {}; } else if (mcpArgs.address) { return { tokenAddresses: [mcpArgs.address] }; } return {}; case 'transfer-token': return { amount: mcpArgs.amount, tokenAddress: mcpArgs.address === '0x0000000000000000000000000000000000000000' ? 'eth' : mcpArgs.address, destination: mcpArgs.to }; case 'swap-tokens': return { tokenIn: mcpArgs.fromToken, tokenOut: mcpArgs.toToken, amount: mcpArgs.amount }; default: return mcpArgs; } } // Convert agentkit actions to MCP tools format function convertToMcpTools() { return [ { name: 'get-address', description: 'Gets the smart account wallet address', inputSchema: { type: 'object', properties: {}, required: [] }, }, { name: 'get-balance', description: 'Gets the balance of tokens in the smart account on BSC', inputSchema: { type: 'object', properties: { address: { type: 'string', description: 'Token contract address (use "0x0000000000000000000000000000000000000000" for native token like BNB/ETH)', }, }, required: [], }, }, { name: 'transfer-token', description: 'Transfer tokens gaslessly to another address', inputSchema: { type: 'object', properties: { to: { type: 'string', description: 'Recipient address', }, address: { type: 'string', description: 'Token contract address (use "0x0000000000000000000000000000000000000000" for native token)', }, amount: { type: 'string', description: 'Amount to transfer', }, }, required: ['to', 'address', 'amount'], }, }, { name: 'swap-tokens', description: 'Swap one token for another gaslessly', inputSchema: { type: 'object', properties: { fromToken: { type: 'string', description: 'Source token address', }, toToken: { type: 'string', description: 'Destination token address', }, amount: { type: 'string', description: 'Amount to swap', }, }, required: ['fromToken', 'toToken', 'amount'], }, }, ]; } // Execute agentkit actions directly async function executeAgentkitAction(toolName, args) { try { const { agentkit, actions } = await initializeAgentkit(); // Get the correct action name const agentkitActionName = MCP_TO_AGENTKIT_MAPPING[toolName]; if (!agentkitActionName) { throw new Error(`No mapping found for MCP tool: ${toolName}`); } // Find the action in the available actions const action = actions.find((a) => a.name === agentkitActionName); if (!action) { throw new Error(`Action ${agentkitActionName} not found in available actions`); } // Convert MCP arguments to AgentKit arguments const actionArgs = convertMcpArgsToAgentkitArgs(toolName, args); // Execute the action with suppressed stdout to prevent JSON parsing errors const result = await withSuppressedStdout(async () => { return await agentkit.run(action, actionArgs); }); return result; } catch (error) { // Provide helpful error messages if (error instanceof Error) { if (error.message.includes('insufficient funds')) { return `Error: Insufficient funds for ${toolName}. Please ensure you have enough balance and gas.`; } if (error.message.includes('invalid address')) { return `Error: Invalid address provided for ${toolName}. Please check the address format.`; } if (error.message.includes('Smart Account is required')) { return `Error: Smart account configuration issue. Please check your environment variables.`; } return `Error executing ${toolName}: ${error.message}`; } return `Error executing ${toolName}: ${String(error)}`; } } // Validation function function validateEnvironment() { const required = ['PRIVATE_KEY', 'RPC_URL', 'API_KEY']; const missing = required.filter(key => !process.env[key]); if (missing.length > 0) { console.error('❌ Missing required environment variables:', missing); return false; } // Validate private key format const privateKey = process.env.PRIVATE_KEY; if (privateKey && !privateKey.startsWith('0x')) { console.error('❌ PRIVATE_KEY should start with 0x'); return false; } console.error('✅ Environment variables validated'); return true; } // Log server info function logServerInfo() { console.error('\n=== 0xGasless MCP SERVER ==='); console.error(`Chain ID: ${process.env.CHAIN_ID || '56 (default)'}`); console.error(`Private Key: ${process.env.PRIVATE_KEY ? '[SET]' : '[NOT SET]'}`); console.error(`API Key: ${process.env.API_KEY ? '[SET]' : '[NOT SET]'}`); console.error('============================\n'); } async function main() { // Log server info and validate environment logServerInfo(); if (!validateEnvironment()) { process.exit(1); } try { // Initialize agentkit early to catch any config issues await initializeAgentkit(); console.error("✅ 0xGasless Agentkit initialized successfully"); } catch (error) { console.error("❌ Failed to initialize Agentkit:", error); process.exit(1); } // Create MCP server const server = new index_js_1.Server({ name: '0xGasless MCP Server', version: version_js_1.version, }, { capabilities: { tools: {}, }, }); // Handle tools list server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => { const mcpTools = convertToMcpTools(); return { tools: mcpTools }; }); // Handle tool calls server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { const result = await executeAgentkitAction(name, args || {}); return { content: [{ type: 'text', text: result }], }; } catch (error) { return { content: [ { type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}`, }, ], }; } }); // Connect to transport const transport = new stdio_js_1.StdioServerTransport(); console.error('🔌 Starting MCP server...'); await server.connect(transport); console.error('✅ 0xGasless MCP Server running'); } //# sourceMappingURL=main.js.map