UNPKG

@cheqd/mcp-toolkit-server

Version:

MCP Toolkit Server for cheqd

197 lines 7.36 kB
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CredoToolKit } from '@cheqd/mcp-toolkit-credo'; import { readFile } from 'fs/promises'; import path from 'path'; import { fileURLToPath } from 'url'; // Get the module's package.json const __dirname = path.dirname(fileURLToPath(import.meta.url)); const packageJsonPath = path.join(__dirname, '../package.json'); const packageJson = JSON.parse(await readFile(packageJsonPath, 'utf-8')); /** * AgentMcpServer extends McpServer to provide specialized functionality * for the cheqd agent, including tool setup, signal handling, and proper cleanup. */ export class AgentMcpServer extends McpServer { transport = null; credoToolkit = null; options; /** * Initialize the server with a name and version, and set up capabilities */ constructor(options) { super({ name: 'cheqd-mcp-toolkit-server', version: packageJson.version, }, { capabilities: { logging: {}, tools: {}, resources: {}, prompts: {}, }, }); // setup signal handling this.setupSignalHandlers(); this.options = options; } /** * Setup signal handlers for proper cleanup */ setupSignalHandlers() { // Handle termination signals process.on('SIGINT', this.cleanup.bind(this)); process.on('SIGTERM', this.cleanup.bind(this)); process.on('disconnect', this.cleanup.bind(this)); // Handle stdin/stdout closing process.stdin.on('close', this.cleanup.bind(this)); process.stdout.on('close', this.cleanup.bind(this)); process.stdin.on('error', () => this.cleanup()); } /** * Get the current status of the MCP server and its tools * @returns A status object with information about the server and agent */ getStatus() { try { // Basic Agent server information const status = { name: 'cheqd-mcp-toolkit-server', version: packageJson.version, uptime: process.uptime(), timestamp: new Date().toISOString(), tools: this.options.tools, healthy: true, }; // Add Credo agent status if (this.credoToolkit?.credo) { const credo = this.credoToolkit.credo; status.credoAgent = { name: credo.name, isInitialized: credo.agent?.isInitialized || false, domain: credo.domain, port: credo.port, }; // Add connection information if the agent is initialized try { if (credo.agent?.isInitialized) { status.credoAgent.walletId = credo.config.walletConfig?.id; // Add credo agent stats status.credoAgent.stats = { uptime: process.uptime(), services: this.transport ? 'connected' : 'disconnected', }; } } catch (error) { status.credoAgent.error = `Error getting detailed agent stats: ${error instanceof Error ? error.message : String(error)}`; } } return status; } catch (error) { return { healthy: false, error: `Failed to retrieve server status: ${error instanceof Error ? error.message : String(error)}`, }; } } /* * Configure and initialize tools, resources and prompts for the server based on env variables */ async setupTools() { // Configure tools through env const tools = []; // Handle Credo Tools if (this.options.tools.includes('credo')) { await this.setupCredoTools(tools); if (this.credoToolkit) { this.credoToolkit.registerResources(this); this.credoToolkit.registerPrompts(this); } } // Register all tools with the server for (const tool of tools) { this.tool(tool.name, tool.description, tool.schema, tool.handler); } } /** * Set up Credo-specific tools */ async setupCredoTools(tools) { // Validate required env variables if (!this.options.credo?.cosmosPayerSeed) { throw new Error('Missing required environment variables for Credo tools. Please set: CREDO_CHEQD_TESTNET_MNEMONIC'); } try { this.credoToolkit = new CredoToolKit({ port: this.options.credo.port, name: this.options.credo.name, mnemonic: this.options.credo.cosmosPayerSeed, endpoint: this.options.credo.domain, }); await this.credoToolkit.init(); const credoTools = await this.credoToolkit.getTools(); tools.push(...credoTools); } catch (err) { throw new Error(`Credo initialization failed: ${err instanceof Error ? err.message : String(err)}`); } } /* * Start the server and connect to the specified transport */ async start(transport) { try { this.transport = transport || new StdioServerTransport(); await this.connect(this.transport); // Send logging notification to client await this.server.sendLoggingMessage({ level: 'debug', data: 'Cheqd MCP Toolkit Server started successfully', }); } catch (err) { console.error('Fatal error in start():', err); process.exit(1); } } /** * Gracefully cleanup the server */ async cleanup() { console.error('Shutdown signal received, cleaning up server...'); try { const { credoToolkit, transport } = this; // Shutdown the agent if available if (credoToolkit) { await credoToolkit.shutdown(); } // Close transport if it's a StdioServerTransport if (transport instanceof StdioServerTransport) { await transport.close(); this.transport = null; // Clear references after shutdown this.credoToolkit = null; } // Force exit after 3 seconds if cleanup hangs const forceExitTimeout = setTimeout(() => { console.error('Forced exit after timeout'); process.exit(1); }, 3000); forceExitTimeout.unref(); // Exit cleanly if transport was of the expected type if (transport instanceof StdioServerTransport) { process.exit(0); } } catch (err) { console.error('Error during cleanup:', err); process.exit(1); } } } // Export other modules export * from './utils.js'; export * from './types/index.js'; //# sourceMappingURL=server.js.map