UNPKG

@gala-chain/launchpad-mcp-server

Version:

MCP server for Gala Launchpad - 102 tools (pool management, event watchers, GSwap DEX trading, price history, token creation, wallet management, DEX pool discovery, liquidity positions, token locks, locked token queries, composite pool data, cross-chain b

317 lines 12.7 kB
"use strict"; /** * Gala Launchpad MCP Server * * Provides MCP tools for AI agents to interact with Gala Launchpad */ Object.defineProperty(exports, "__esModule", { value: true }); exports.LaunchpadMCPServer = void 0; 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 launchpad_sdk_1 = require("@gala-chain/launchpad-sdk"); const index_js_2 = require("./tools/index.js"); const index_js_3 = require("./prompts/index.js"); const version_js_1 = require("./generated/version.js"); class LaunchpadMCPServer { server; sdk = null; debug; currentEnvironment = 'production'; currentPrivateKey; constructor() { this.debug = process.env.DEBUG === 'true'; this.server = new index_js_1.Server({ name: '@gala-chain/launchpad-mcp-server', version: version_js_1.MCP_SERVER_VERSION, }, { capabilities: { tools: {}, prompts: { listChanged: true, }, }, }); this.setupToolHandlers(); this.setupPromptHandlers(); this.setupErrorHandlers(); } /** * Initialize SDK with AgentConfig * * Supports two operational modes: * 1. Full-access mode (PRIVATE_KEY provided): Uses quickSetup() - all operations available * 2. Read-only mode (PRIVATE_KEY not provided): Uses readOnlySetup() - query operations only * * In read-only mode, signing operations (buy, sell, create tokens, etc.) will throw ValidationError * when attempted, but all query operations (fetchPools, fetchBalance, etc.) work normally. */ async initialize() { try { if (this.debug) { console.error('[MCP Server] Initializing SDK...'); } const hasPrivateKey = Boolean(process.env.PRIVATE_KEY && process.env.PRIVATE_KEY.trim()); const environment = (process.env.ENVIRONMENT || 'production'); const timeout = parseInt(process.env.TIMEOUT || '30000', 10); // Store environment and private key for dynamic switching this.currentEnvironment = environment; if (hasPrivateKey) { this.currentPrivateKey = process.env.PRIVATE_KEY; } if (hasPrivateKey) { // Full-access mode: use quickSetup() to enable signing operations if (this.debug) { console.error('[MCP Server] PRIVATE_KEY detected - initializing in full-access mode'); } const { sdk, validation } = await launchpad_sdk_1.AgentConfig.quickSetup({ environment, privateKey: process.env.PRIVATE_KEY, timeout, debug: this.debug, autoValidate: false, }); this.sdk = sdk; if (this.debug) { console.error('[MCP Server] SDK initialized successfully (full-access mode)'); if (validation) { console.error(`[MCP Server] Validation - Ready: ${validation.ready}`); console.error(`[MCP Server] Validation - Can Trade: ${validation.capabilities.canTrade}`); } } if (validation && !validation.ready) { console.error('[MCP Server] Warning: SDK not ready', validation.issues); } } else { // Read-only mode: use readOnlySetup() for query-only operations if (this.debug) { console.error('[MCP Server] PRIVATE_KEY not provided - initializing in read-only mode'); } const { sdk } = await launchpad_sdk_1.AgentConfig.readOnlySetup({ environment, timeout, debug: this.debug, }); this.sdk = sdk; if (this.debug) { console.error('[MCP Server] SDK initialized successfully (read-only mode)'); console.error('[MCP Server] Note: Signing operations will fail - wallet required'); } } } catch (error) { console.error('[MCP Server] Failed to initialize SDK:', error); throw error; } } /** * Setup tool handlers */ setupToolHandlers() { // Register tools/list handler this.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => { if (this.debug) { console.error(`[MCP Server] Listing ${index_js_2.tools.length} tools`); } return { tools: index_js_2.tools.map((tool) => ({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema, })), }; }); // Register tools/call handler this.server.setRequestHandler(types_js_1.CallToolRequestSchema, // eslint-disable-next-line @typescript-eslint/no-explicit-any -- MCP SDK handler type incompatibility - returns MCPToolResponse which works at runtime but doesn't match MCP SDK's complex Zod-validated response types async (request, _extra) => { const toolName = request.params.name; const args = request.params.arguments || {}; if (this.debug) { console.error(`[MCP Server] Executing tool: ${toolName}`); console.error(`[MCP Server] Arguments:`, JSON.stringify(args, null, 2)); } const tool = index_js_2.tools.find((t) => t.name === toolName); if (!tool) { throw new Error(`Tool not found: ${toolName}`); } if (!this.sdk) { throw new Error('SDK not initialized. Failed during startup - check logs for details.'); } try { const result = await tool.handler(this.sdk, args, this); if (this.debug) { console.error(`[MCP Server] Tool execution successful: ${toolName}`); } return result; } catch (error) { console.error(`[MCP Server] Tool execution failed: ${toolName}`, error); throw error; } }); } /** * Setup prompt handlers */ setupPromptHandlers() { // Register prompts/list handler this.server.setRequestHandler(types_js_1.ListPromptsRequestSchema, async () => { if (this.debug) { console.error(`[MCP Server] Listing ${index_js_3.prompts.length} prompts`); } return { prompts: index_js_3.prompts.map((prompt) => ({ name: prompt.name, description: prompt.description, arguments: prompt.arguments || [], })), }; }); // Register prompts/get handler this.server.setRequestHandler(types_js_1.GetPromptRequestSchema, async (request) => { const promptName = request.params.name; const args = (request.params.arguments || {}); if (this.debug) { console.error(`[MCP Server] Getting prompt: ${promptName}`); console.error(`[MCP Server] Arguments:`, JSON.stringify(args, null, 2)); } const prompt = (0, index_js_3.getPrompt)(promptName); if (!prompt) { throw new Error(`Prompt not found: ${promptName}`); } try { const messages = prompt.handler(args); if (this.debug) { console.error(`[MCP Server] Prompt generated ${messages.length} messages`); } return { messages, }; } catch (error) { console.error(`[MCP Server] Prompt generation failed: ${promptName}`, error); throw error; } }); } /** * Setup error handlers */ setupErrorHandlers() { this.server.onerror = (error) => { console.error('[MCP Server] Protocol error:', error); }; process.on('SIGINT', () => { if (this.debug) { console.error('[MCP Server] Received SIGINT, shutting down...'); } this.cleanup(); process.exit(0); }); process.on('SIGTERM', () => { if (this.debug) { console.error('[MCP Server] Received SIGTERM, shutting down...'); } this.cleanup(); process.exit(0); }); } /** * Start the MCP server */ async start() { await this.initialize(); const transport = new stdio_js_1.StdioServerTransport(); await this.server.connect(transport); if (this.debug) { console.error('[MCP Server] Gala Launchpad MCP server running on stdio'); console.error(`[MCP Server] Registered ${index_js_2.tools.length} tools`); console.error(`[MCP Server] Registered ${index_js_3.prompts.length} prompts (slash commands)`); } } /** * Switch to a different environment dynamically * Creates a new SDK instance with the new environment while preserving the wallet * * Strategy: Create new SDK BEFORE destroying old one to avoid broken state on error */ async switchEnvironment(newEnvironment) { try { if (this.debug) { console.error(`[MCP Server] Switching environment: ${this.currentEnvironment}${newEnvironment}`); } const previousEnvironment = this.currentEnvironment; const previousSdk = this.sdk; const timeout = parseInt(process.env.TIMEOUT || '30000', 10); // Create new SDK BEFORE destroying old one (prevents broken state on error) let newSdk; if (this.currentPrivateKey) { // Preserve wallet in full-access mode if (this.debug) { console.error('[MCP Server] Switching with wallet preservation (full-access mode)'); } const { sdk } = await launchpad_sdk_1.AgentConfig.quickSetup({ environment: newEnvironment, privateKey: this.currentPrivateKey, timeout, debug: this.debug, autoValidate: false, }); newSdk = sdk; } else { // Switch in read-only mode if (this.debug) { console.error('[MCP Server] Switching in read-only mode'); } const { sdk } = await launchpad_sdk_1.AgentConfig.readOnlySetup({ environment: newEnvironment, timeout, debug: this.debug, }); newSdk = sdk; } // Only cleanup old SDK after new one is successfully created and ready if (previousSdk) { previousSdk.cleanup(); } // Now safe to update SDK instance and environment this.sdk = newSdk; this.currentEnvironment = newEnvironment; if (this.debug) { console.error(`[MCP Server] Environment switched successfully: ${previousEnvironment}${newEnvironment}`); } return { success: true, previousEnvironment, newEnvironment, }; } catch (error) { console.error('[MCP Server] Failed to switch environment:', error); // Old SDK remains intact if switch fails throw error; } } /** * Get current environment */ getEnvironment() { return this.currentEnvironment; } /** * Cleanup resources */ cleanup() { if (this.sdk) { this.sdk.cleanup(); if (this.debug) { console.error('[MCP Server] SDK cleaned up'); } } } } exports.LaunchpadMCPServer = LaunchpadMCPServer; //# sourceMappingURL=server.js.map