Skip to main content
Glama

MCP Desktop Automation

server.js5.75 kB
#!/usr/bin/env node // Import required packages const screenshot = require('screenshot-desktop'); const robot = require('robotjs'); const { McpServer, ResourceTemplate } = require("@modelcontextprotocol/sdk/server/mcp.js"); const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js"); const { z } = require("zod"); const packageJson = require('./package.json'); // Create server instance const server = new McpServer( { name: "mcp-desktop-automation", version: packageJson.version, }, { capabilities: { resources: {}, tools: {}, logging: {}, }, }, ); const screenshots = {}; // Implementation of capabilities const capabilityImplementations = { screen_capture: async (params = {}) => { try { // Take a screenshot const img = await screenshot(); const imgInBase64 = img.toString('base64'); const timestamp = Math.floor(Date.now() / 1000); const screenshotKey = `screenshot-${timestamp}`; screenshots[screenshotKey] = imgInBase64; await server.server.sendResourceListChanged(); return { content: [ { type: "text", text: `Screenshot ${screenshotKey} taken.`, }, { type: "image", mimeType: "image/png", data: imgInBase64, }, ], isError: false }; } catch (error) { console.error('Error capturing screen:', error); return { success: false, error: error.message }; } }, mouse_move: (params) => { try { const { x, y } = params; robot.moveMouse(x, y); return { success: true }; } catch (error) { console.error('Error moving mouse:', error); return { success: false, error: error.message }; } }, mouse_click: (params = {}) => { try { const { button = 'left', double = false } = params; if (double) { robot.mouseClick(button, double); } else { robot.mouseClick(button); } return { success: true }; } catch (error) { console.error('Error clicking mouse:', error); return { success: false, error: error.message }; } }, keyboard_type: (params) => { try { const { text } = params; robot.typeString(text); return { success: true }; } catch (error) { console.error('Error typing text:', error); return { success: false, error: error.message }; } }, keyboard_press: (params) => { try { const { key, modifiers = [] } = params; if (modifiers.length === 0) { robot.keyTap(key); } else { robot.keyToggle(key, 'down', modifiers); robot.keyToggle(key, 'up'); } return { success: true }; } catch (error) { console.error('Error pressing key:', error); return { success: false, error: error.message }; } }, get_screen_size: () => { try { const size = robot.getScreenSize(); return { success: true, result: size }; } catch (error) { console.error('Error getting screen size:', error); return { success: false, error: error.message }; } } }; function toMcpResponse(obj) { return { content: [ { type: "text", text: JSON.stringify(obj), }, ], }; } server.tool("get_screen_size", "Gets the screen dimensions", {}, async () => toMcpResponse(capabilityImplementations.get_screen_size())); server.tool("screen_capture", "Captures the current screen content", {}, async () => capabilityImplementations.screen_capture()); server.tool("keyboard_press", "Presses a keyboard key or key combination", { key: z.string().describe("Key to press (e.g., 'enter', 'a', 'control')"), modifiers: z.array(z.enum(["control", "shift", "alt", "command"])).default([]).describe("Modifier keys to hold while pressing the key") }, async (params) => toMcpResponse(capabilityImplementations.keyboard_press(params))); server.tool("keyboard_type", "Types text at the current cursor position", { text: z.string().describe("Text to type") }, async (params) => toMcpResponse(capabilityImplementations.keyboard_type(params))); server.tool("mouse_click", "Performs a mouse click", { button: z.enum(["left", "right", "middle"]).default("left").describe("Mouse button to click"), double: z.boolean().default(false).describe("Whether to perform a double click") }, async (params) => toMcpResponse(capabilityImplementations.mouse_click(params))); server.tool("mouse_move", "Moves the mouse to specified coordinates", { x: z.number().describe("X coordinate"), y: z.number().describe("Y coordinate") }, async (params) => toMcpResponse(capabilityImplementations.mouse_move(params))); server.resource( "screenshot-list", "screenshot://list", async (uri) => { const result = { contents: [ ...Object.keys(screenshots).map(name => ({ uri: `screenshot://${name}`, mimeType: "image/png", blob: screenshots[name], })), ] }; server.server.sendLoggingMessage({level: "info", data: `Returned ${JSON.stringify(result)}`}); console.error(`Returned ${JSON.stringify(result)}`); return result; } ); server.resource( "screenshot-content", new ResourceTemplate("screenshot://{id}", { list: undefined }), async (uri, { id }) => ({ contents: [{ uri: uri.href, mimeType: "image/png", blob: screenshots[id], }] }) ); async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("Robot MCP Server running on stdio"); } main().catch((error) => { console.error("Fatal error in main():", 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/tanob/mcp-desktop-automation'

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