UNPKG

spex-mcp

Version:

MCP server for Figma SpeX plugin and Cursor AI integration

163 lines (143 loc) • 5.54 kB
#!/usr/bin/env node import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js"; import { createRequire } from 'module'; import { FigmaPluginManager } from "./figma-functions.js"; import { MCPToolsManager } from "./mcp-tools.js"; // Read version from package.json const require = createRequire(import.meta.url); const packageJson = require('../../package.json'); /** * Main SpeX MCP Server that orchestrates both Figma SpeX plugin communication * and MCP tools for Cursor AI integration */ class SpeXMCPServer { constructor(port = 8080, force = false) { // Initialize managers this.figmaManager = new FigmaPluginManager(port, force); this.mcpToolsManager = new MCPToolsManager(this.figmaManager); // Initialize MCP server this.server = new Server( { name: packageJson.name, version: packageJson.version, }, { capabilities: { tools: {}, }, } ); this.setupMCPHandlers(); } /** * Setup MCP request handlers for Cursor AI integration */ setupMCPHandlers() { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: this.mcpToolsManager.getToolsList(), }; }); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; return await this.mcpToolsManager.handleToolCall(name, args); }); } /** * Start the server with both Figma SpeX WebSocket and MCP connections */ async run() { try { // Start WebSocket server for Figma SpeX plugins await this.figmaManager.setupWebSocketServer(); console.error(`āœ… Figma SpeX WebSocket server started on port ${this.figmaManager.port}`); // Start MCP server for Cursor AI const transport = new StdioServerTransport(); await this.server.connect(transport); console.error("āœ… MCP server started for Cursor AI integration"); // Setup graceful shutdown this.setupGracefulShutdown(); } catch (error) { console.error("āŒ Error starting SpeX MCP Server:", error); process.exit(1); } } /** * Setup graceful shutdown handlers */ setupGracefulShutdown() { const shutdown = async () => { console.error("\nšŸ”„ Shutting down SpeX MCP Server..."); try { await this.figmaManager.shutdown(); console.error("āœ… Server shutdown completed"); } catch (error) { console.error("āŒ Error during shutdown:", error); } process.exit(0); }; process.on('SIGINT', shutdown); process.on('SIGTERM', shutdown); process.on('uncaughtException', (error) => { console.error('āŒ Uncaught Exception:', error); shutdown(); }); process.on('unhandledRejection', (reason, promise) => { console.error('āŒ Unhandled Rejection at:', promise, 'reason:', reason); shutdown(); }); } } // Parse command line arguments function parseArgs() { const args = process.argv.slice(2); const config = { port: 8080, force: false }; console.error(`šŸ”§ Parsing arguments: ${JSON.stringify(args)}`); for (let i = 0; i < args.length; i++) { if (args[i] === '--port' && i + 1 < args.length) { const port = parseInt(args[i + 1]); if (isNaN(port) || port < 1 || port > 65535) { console.error("āŒ Invalid port number. Must be between 1 and 65535."); process.exit(1); } config.port = port; i++; // Skip the next argument since it's the port value } else if (args[i] === '--force') { config.force = true; console.error(`šŸ”§ Force option enabled`) } else if (args[i] === '--version' || args[i] === '-v') { console.error(`spex-mcp version ${packageJson.version}`); process.exit(0); } else if (args[i] === '--help' || args[i] === '-h') { console.error(` SpeX MCP Server - Figma SpeX plugin integration with Cursor AI Usage: node src/local/index.js [options] Options: --port <number> WebSocket server port (default: 8080) --force Force kill any process using the port before starting --version, -v Show version number --help, -h Show this help message Examples: node src/local/index.js --port 3000 node src/local/index.js --force node src/local/index.js --port 3000 --force node src/local/index.js --version node src/local/index.js `); process.exit(0); } } console.error(`šŸ”§ Final config: ${JSON.stringify(config)}`); return config; } // Start the server const config = parseArgs(); const server = new SpeXMCPServer(config.port, config.force); server.run().catch((error) => { console.error("āŒ Failed to start server:", error); process.exit(1); });