@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
JavaScript
;
/**
* 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