Skip to main content
Glama

Cursor MCP Server

by johnneerdael
base-manager.ts6.06 kB
import { WindowManager, WindowInfo, WindowEvent } from './types.js' import * as activeWin from 'active-win' import { EventEmitter } from 'events' import { InputAutomationService } from '../input-automation/input-service.js' import { WindowManagerError, WindowNotFoundError, WindowFocusError, WindowResponseError, InputAutomationError } from '../../errors/window-manager-errors.js' import { log } from '../../utils/logger.js' export abstract class BaseWindowManager implements WindowManager { protected eventEmitter = new EventEmitter() protected windowCache = new Map<number, WindowInfo>() protected inputService: InputAutomationService protected logger = log.child('WindowManager') constructor() { this.inputService = InputAutomationService.getInstance() this.logger.info('Window manager initialized', { platform: process.platform }) } protected convertToWindowInfo(activeWindow: activeWin.Result): WindowInfo { const cached = this.windowCache.get(activeWindow.owner.processId) if (cached) { this.logger.debug('Using cached window info', { processId: activeWindow.owner.processId }) return cached } const windowInfo: WindowInfo = { id: activeWindow.owner.processId, title: activeWindow.title, processId: activeWindow.owner.processId, bounds: { x: activeWindow.bounds.x, y: activeWindow.bounds.y, width: activeWindow.bounds.width, height: activeWindow.bounds.height } } this.windowCache.set(activeWindow.owner.processId, windowInfo) this.logger.debug('Created new window info', { windowInfo }) return windowInfo } async getActiveWindow(): Promise<WindowInfo | null> { try { const window = await activeWin.activeWindow() if (!window) { this.logger.debug('No active window found') return null } return this.convertToWindowInfo(window) } catch (error) { this.logger.error('Error getting active window', { error: error instanceof Error ? error.message : String(error) }) return null } } abstract getAllWindows(): Promise<WindowInfo[]> async findWindowByTitle(title: string): Promise<WindowInfo | null> { this.logger.debug('Finding window by title', { title }) const windows = await this.getAllWindows() const window = windows.find(w => w.title.includes(title)) if (!window) { this.logger.debug('Window not found by title', { title }) throw new WindowNotFoundError(title) } return window } async findWindowByProcessId(processId: number): Promise<WindowInfo | null> { this.logger.debug('Finding window by process ID', { processId }) const windows = await this.getAllWindows() const window = windows.find(w => w.processId === processId) if (!window) { this.logger.debug('Window not found by process ID', { processId }) throw new WindowNotFoundError(processId) } return window } abstract focusWindow(windowInfo: WindowInfo): Promise<boolean> abstract closeWindow(windowInfo: WindowInfo): Promise<boolean> async isWindowResponding(windowInfo: WindowInfo): Promise<boolean> { try { const window = await this.findWindowByProcessId(windowInfo.processId) if (!window) { throw new WindowResponseError('Window not found') } return true } catch (error) { if (error instanceof WindowManagerError) { this.logger.warn('Window not responding', { processId: windowInfo.processId, error: error.message }) return false } throw error } } on(event: WindowEvent['type'], callback: (event: WindowEvent) => void): void { this.logger.debug('Adding event listener', { event }) this.eventEmitter.on(event, callback) } off(event: WindowEvent['type'], callback: (event: WindowEvent) => void): void { this.logger.debug('Removing event listener', { event }) this.eventEmitter.off(event, callback) } async sendKeys(windowInfo: WindowInfo, keys: string[]): Promise<void> { try { this.logger.debug('Sending keys to window', { processId: windowInfo.processId, keys }) const focused = await this.focusWindow(windowInfo) if (!focused) { throw new WindowFocusError('Failed to focus window before sending keys') } await this.inputService.sendKeys(keys) } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error) this.logger.error('Error sending keys', { processId: windowInfo.processId, keys, error: errorMessage }) throw new InputAutomationError(`Failed to send keys: ${errorMessage}`) } } async sendMouseClick(x: number, y: number, button: 'left' | 'right' = 'left'): Promise<void> { try { this.logger.debug('Sending mouse click', { x, y, button }) await this.inputService.moveMouse(x, y) await this.inputService.mouseClick(button) } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : String(error) this.logger.error('Error sending mouse click', { x, y, button, error: errorMessage }) throw new InputAutomationError(`Failed to send mouse click: ${errorMessage}`) } } abstract getPlatformSpecificApi(): any }

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/johnneerdael/multiplatform-cursor-mcp'

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