UNPKG

@hrrrsn/mcp-vnc

Version:

Model Context Protocol (MCP) server enabling AI agents to control remote desktops

158 lines (157 loc) 7.06 kB
// src/server.ts import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import { VncConnectionManager } from './vnc/client.js'; import { readFileSync } from 'fs'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8')); import { handleClick, handleMoveMouse, handleKeyPress, handleTypeText, handleTypeMultiline, handleScreenshot } from './tools/index.js'; export class VncMcpServer { server; vncManager; constructor(config) { this.vncManager = new VncConnectionManager(config); this.server = new Server({ name: 'vnc-control-server', version: packageJson.version, }, { capabilities: { tools: {}, }, }); this.setupTools(); } setupTools() { this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: 'vnc_click', description: 'Click at specified coordinates', inputSchema: { type: 'object', properties: { x: { type: 'number', description: 'X coordinate' }, y: { type: 'number', description: 'Y coordinate' }, button: { type: 'string', description: 'Mouse button', enum: ['left', 'right', 'middle'], default: 'left' }, double: { type: 'boolean', description: 'Double-click instead of single click', default: false } }, required: ['x', 'y'] } }, { name: 'vnc_move_mouse', description: 'Move mouse to specified coordinates', inputSchema: { type: 'object', properties: { x: { type: 'number', description: 'X coordinate' }, y: { type: 'number', description: 'Y coordinate' } }, required: ['x', 'y'] } }, { name: 'vnc_key_press', description: 'Press a key or key combination', inputSchema: { type: 'object', properties: { key: { type: 'string', description: 'Key to press. Single keys: "a", "Enter", "F1". Combinations: "Ctrl+c", "Alt+F4", "Ctrl+Alt+Delete", "Shift+Tab"' } }, required: ['key'] } }, { name: 'vnc_type_text', description: 'Type text string', inputSchema: { type: 'object', properties: { text: { type: 'string', description: 'Single line of text to type' }, enter: { type: 'boolean', description: 'Press Enter after typing text', default: false } }, required: ['text'] } }, { name: 'vnc_type_multiline', description: 'Type multiple lines of text, separated by newlines', inputSchema: { type: 'object', properties: { lines: { type: 'array', items: { type: 'string' }, description: 'Array of lines to type' } }, required: ['lines'] } }, { name: 'vnc_screenshot', description: 'Take a screenshot of the current screen', inputSchema: { type: 'object', properties: { delay: { type: 'number', description: 'Delay in milliseconds before taking screenshot (useful for waiting for processes to complete)', minimum: 0, maximum: 300000, default: 0 } } } } ] }; }); this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { case 'vnc_click': return await handleClick(this.vncManager, args); case 'vnc_move_mouse': return await handleMoveMouse(this.vncManager, args); case 'vnc_key_press': return await handleKeyPress(this.vncManager, args); case 'vnc_type_text': return await handleTypeText(this.vncManager, args); case 'vnc_type_multiline': return await handleTypeMultiline(this.vncManager, args); case 'vnc_screenshot': return await handleScreenshot(this.vncManager, args); default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { return { content: [ { type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` } ] }; } }); } async run() { try { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error(`mcp-vnc ${packageJson.version} started!`); } catch (error) { console.error('Failed to start mcp-vnc: ', error); process.exit(1); } } }