Skip to main content
Glama

Cursor MCP Server

by Buga-luga
cursor-tool.ts6.38 kB
import robot from 'robotjs' import { spawn } from 'child_process' import path from 'path' import { windowManager } from 'node-window-manager' import { getPaletteCommand, CommandSchema } from '../commands/cursor-commands.js' const DEFAULT_CURSOR_PATH = path.join(process.env.LOCALAPPDATA || '', 'Programs', 'cursor', 'Cursor.exe') async function findCursorWindow(): Promise<any> { const windows = windowManager.getWindows() return windows.find(w => w.getTitle().includes('Cursor')) } async function ensureCursorFocus(cursorWindow: any): Promise<boolean> { // Get currently active window const windows = windowManager.getWindows() const activeWindow = windows.find(w => w.getTitle().includes('Cursor')) // Check if Cursor is already focused if (activeWindow) { return true } // If not focused, try to restore focus console.log('Restoring Cursor window focus...') cursorWindow.bringToTop() cursorWindow.show() cursorWindow.restore() // Wait for focus change await new Promise(resolve => setTimeout(resolve, 500)) // Verify focus was restored const newWindows = windowManager.getWindows() const newActiveWindow = newWindows.find(w => w.getTitle().includes('Cursor')) return !!newActiveWindow } async function typeText(text: string, cursorWindow: any) { for (const char of text) { // Ensure focus before each keystroke if (!await ensureCursorFocus(cursorWindow)) { console.log('Failed to maintain Cursor window focus') throw new Error('Lost window focus') } // Handle uppercase letters if (char >= 'A' && char <= 'Z') { robot.keyToggle('shift', 'down') await new Promise(resolve => setTimeout(resolve, 50)) robot.keyTap(char.toLowerCase()) await new Promise(resolve => setTimeout(resolve, 50)) robot.keyToggle('shift', 'up') await new Promise(resolve => setTimeout(resolve, 50)) } // Handle special characters else if (char === ':') { robot.keyToggle('shift', 'down') await new Promise(resolve => setTimeout(resolve, 50)) robot.keyTap(';') // On most keyboards, shift+; gives : await new Promise(resolve => setTimeout(resolve, 50)) robot.keyToggle('shift', 'up') await new Promise(resolve => setTimeout(resolve, 50)) } // Handle spaces else if (char === ' ') { robot.keyTap('space') await new Promise(resolve => setTimeout(resolve, 50)) } // Handle normal lowercase letters else { robot.keyTap(char) await new Promise(resolve => setTimeout(resolve, 50)) } } } async function executeCursorCommand(commandName: string) { // Validate command const parseResult = CommandSchema.safeParse({ command: commandName }) if (!parseResult.success) { throw new Error(`Invalid command: ${commandName}. Available commands: ${Object.keys(CommandSchema.shape.command.enum).join(', ')}`) } // Get the palette command const paletteCommand = getPaletteCommand(commandName) if (!paletteCommand) { throw new Error(`No palette command found for: ${commandName}`) } try { console.log('Launching Cursor...') const cursorProcess = spawn(DEFAULT_CURSOR_PATH, [], { detached: false, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: false }) // Wait for Cursor to start console.log('Waiting for Cursor to initialize...') await new Promise(resolve => setTimeout(resolve, 3000)) // Find the Cursor window const cursorWindow = await findCursorWindow() if (!cursorWindow) { throw new Error('Could not find Cursor window') } // Initial focus console.log('Focusing Cursor window...') if (!await ensureCursorFocus(cursorWindow)) { throw new Error('Failed to focus Cursor window') } console.log('Opening command palette...') // Press Ctrl+Shift+P using robotjs robot.keyToggle('control', 'down') await new Promise(resolve => setTimeout(resolve, 50)) robot.keyToggle('shift', 'down') await new Promise(resolve => setTimeout(resolve, 50)) robot.keyToggle('p', 'down') await new Promise(resolve => setTimeout(resolve, 50)) // Release in reverse order with delays robot.keyToggle('p', 'up') await new Promise(resolve => setTimeout(resolve, 50)) robot.keyToggle('shift', 'up') await new Promise(resolve => setTimeout(resolve, 50)) robot.keyToggle('control', 'up') await new Promise(resolve => setTimeout(resolve, 50)) // Wait for command palette to appear await new Promise(resolve => setTimeout(resolve, 500)) // Type the command with focus checks console.log('Executing command:', paletteCommand) await typeText(paletteCommand, cursorWindow) // Wait briefly after typing await new Promise(resolve => setTimeout(resolve, 500)) // Ensure focus before Enter if (!await ensureCursorFocus(cursorWindow)) { throw new Error('Lost window focus before pressing Enter') } // Press Enter console.log('Confirming command...') robot.keyTap('enter') // Keep process alive briefly to observe result await new Promise(resolve => setTimeout(resolve, 2000)) // Cleanup console.log('Done!') cursorProcess.kill() } catch (error) { console.error('Command failed:', error) process.exit(1) } } // Get command from command line const commandName = process.argv[2] if (!commandName) { console.log('Available commands:') Object.entries(CommandSchema.shape.command.enum).forEach(([cmd]) => { console.log(`- ${cmd}`) }) process.exit(0) } // Execute the command console.log(`Executing Cursor command: ${commandName}`) executeCursorCommand(commandName).catch(error => { console.error('Unhandled error:', error) process.exit(1) })

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Buga-luga/cursor-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server