index.ts•3.44 kB
/**
 * Figma MCP Server - Main entry point
 *
 * This server provides a Model Context Protocol (MCP) implementation
 * for interacting with the Figma API.
 */
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { execSync } from "child_process";
import * as dotenv from "dotenv";
import { env } from "./config/env.js";
import { registerAllResources } from "./resources.js";
import { initializeWebSocketServer } from "./services/websocket.js";
import { registerAllTools } from "./tools/index.js";
import { log } from "./utils.js";
// Load environment variables
dotenv.config();
// Check for and kill any existing processes using the same port
function killExistingProcesses() {
  try {
    const wsPort = env.WEBSOCKET_PORT || 3001;
    log(`Checking for processes using port ${wsPort}...`);
    // Find processes using the websocket port
    const findCmd =
      process.platform === "win32"
        ? `netstat -ano | findstr :${wsPort}`
        : `lsof -i:${wsPort} | grep LISTEN`;
    let output;
    try {
      output = execSync(findCmd, { encoding: "utf8" });
    } catch (e) {
      // No process found, which is fine
      log("No existing processes found.");
      return;
    }
    // Extract PIDs and kill them
    if (output) {
      if (process.platform === "win32") {
        // Windows: extract PID from last column
        const pids = output
          .split("\n")
          .filter((line) => line.trim())
          .map((line) => line.trim().split(/\s+/).pop())
          .filter((pid, index, self) => pid && self.indexOf(pid) === index);
        pids.forEach((pid) => {
          if (pid && parseInt(pid) !== process.pid) {
            try {
              execSync(`taskkill /F /PID ${pid}`);
              log(`Killed process with PID: ${pid}`);
            } catch (e) {
              log(`Failed to kill process with PID: ${pid}`);
            }
          }
        });
      } else {
        // Unix-like: extract PID from second column
        const pids = output
          .split("\n")
          .filter((line) => line.trim())
          .map((line) => {
            const parts = line.trim().split(/\s+/);
            return parts[1];
          })
          .filter((pid, index, self) => pid && self.indexOf(pid) === index);
        pids.forEach((pid) => {
          if (pid && parseInt(pid) !== process.pid) {
            try {
              execSync(`kill -9 ${pid}`);
              log(`Killed process with PID: ${pid}`);
            } catch (e) {
              log(`Failed to kill process with PID: ${pid}`);
            }
          }
        });
      }
    }
  } catch (error) {
    log(`Error checking for existing processes: ${error}`);
  }
}
// Kill any existing processes before starting
killExistingProcesses();
// Create an MCP server
const server = new McpServer({
  name: "Figma API",
  version: "1.0.0",
});
// Register all tools and resources
registerAllTools(server);
registerAllResources(server);
// Initialize WebSocket server for Figma plugin communication
const wsPort = env.WEBSOCKET_PORT || 3001;
initializeWebSocketServer(wsPort);
// Start the MCP server with stdio transport
const transport = new StdioServerTransport();
server.connect(transport);
// Use logger utility to avoid interfering with stdout used by MCP
log("Figma MCP Server started");
export { server };