Skip to main content
Glama
mario-andreschak

MCP Windows Desktop Automation

index.ts6.48 kB
/** * Resources module for MCP Windows Desktop Automation */ import { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'; import * as fs from 'fs/promises'; import * as path from 'path'; import * as autoIt from 'node-autoit-koffi'; import { log } from '../utils/logger/logger'; /** * Register all resources with the MCP server */ export function registerAllResources(server: McpServer): void { // Register file resources registerFileResources(server); // Register screenshot resources registerScreenshotResources(server); } /** * Register file resources */ function registerFileResources(server: McpServer): void { server.resource( 'file', new ResourceTemplate('file://{path*}', { list: async () => { return { resources: [] }; // Empty list by default } }), async (uri, params) => { try { // Ensure filePath is a string const filePath = Array.isArray(params.path) ? params.path.join('/') : params.path; log.verbose('Reading file resource', JSON.stringify({ uri: uri.href, filePath })); // Check if file exists const stats = await fs.stat(filePath); if (stats.isDirectory()) { // List directory contents const files = await fs.readdir(filePath); const resources = await Promise.all( files.map(async (file) => { const fullPath = path.join(filePath, file); const fileStats = await fs.stat(fullPath); return { uri: `file://${fullPath.replace(/\\/g, '/')}`, name: file, description: fileStats.isDirectory() ? 'Directory' : 'File' }; }) ); return { contents: [{ uri: uri.href, text: `Directory: ${filePath}\n${files.join('\n')}`, mimeType: 'text/plain' }] }; } else { // Read file content const content = await fs.readFile(filePath); const extension = path.extname(filePath).toLowerCase(); // Determine if it's a text or binary file const isTextFile = [ '.txt', '.md', '.js', '.ts', '.html', '.css', '.json', '.xml', '.csv', '.log', '.ini', '.cfg', '.conf', '.py', '.c', '.cpp', '.h', '.java', '.sh', '.bat', '.ps1' ].includes(extension); if (isTextFile) { return { contents: [{ uri: uri.href, text: content.toString('utf-8'), mimeType: getMimeType(extension) }] }; } else { return { contents: [{ uri: uri.href, blob: content.toString('base64'), mimeType: getMimeType(extension) }] }; } } } catch (error) { log.error('Error reading file resource', error); throw new Error(`Failed to read file: ${error instanceof Error ? error.message : String(error)}`); } } ); } /** * Register screenshot resources */ function registerScreenshotResources(server: McpServer): void { server.resource( 'screenshot', new ResourceTemplate('screenshot://{window?}', { list: async () => { return { resources: [] }; // Empty list by default } }), async (uri, params) => { try { await autoIt.init(); // Ensure window is a string if provided const windowName = params.window ? String(params.window) : undefined; log.verbose('Taking screenshot', JSON.stringify({ uri: uri.href, window: windowName })); // If window parameter is provided, activate that window first if (windowName) { const windowExists = await autoIt.winExists(windowName); if (windowExists) { await autoIt.winActivate(windowName); // Wait a moment for the window to activate await new Promise(resolve => setTimeout(resolve, 500)); } else { throw new Error(`Window "${windowName}" not found`); } } // TODO: Implement actual screenshot capture // This is a placeholder - in a real implementation, you would use // a library like 'screenshot-desktop' or other Windows API bindings // to capture the screen or specific window // For now, we'll return a placeholder message return { contents: [{ uri: uri.href, text: `Screenshot of ${windowName || 'full screen'} would be captured here`, mimeType: 'text/plain' }] }; // In a real implementation, you would return something like: /* return { contents: [{ uri: uri.href, blob: screenshotBase64Data, mimeType: 'image/png' }] }; */ } catch (error) { log.error('Error taking screenshot', error); throw new Error(`Failed to take screenshot: ${error instanceof Error ? error.message : String(error)}`); } } ); } /** * Get MIME type based on file extension */ function getMimeType(extension: string): string { const mimeTypes: Record<string, string> = { '.txt': 'text/plain', '.html': 'text/html', '.css': 'text/css', '.js': 'application/javascript', '.ts': 'application/typescript', '.json': 'application/json', '.xml': 'application/xml', '.md': 'text/markdown', '.csv': 'text/csv', '.png': 'image/png', '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.gif': 'image/gif', '.svg': 'image/svg+xml', '.pdf': 'application/pdf', '.doc': 'application/msword', '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', '.xls': 'application/vnd.ms-excel', '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', '.ppt': 'application/vnd.ms-powerpoint', '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation', '.zip': 'application/zip', '.rar': 'application/x-rar-compressed', '.7z': 'application/x-7z-compressed', '.tar': 'application/x-tar', '.gz': 'application/gzip' }; return mimeTypes[extension] || 'application/octet-stream'; }

Latest Blog Posts

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/mario-andreschak/mcp-windows-desktop-automation'

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