rustdesk-mcp
Drives the local RustDesk client to launch and manage remote desktop sessions, capture session windows, inject keyboard and mouse input, and maintain a device book of peers with aliases and notes.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@rustdesk-mcpconnect to peer 123456789, screenshot it, and click the OK button"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
rustdesk-mcp
An MCP (Model Context Protocol) server that lets AI agents control remote desktops through the local RustDesk client on macOS.
Instead of re-implementing a remote-desktop stack, rustdesk-mcp drives the RustDesk app you already have: it launches sessions, captures the session window, and injects keyboard/mouse input — exposing all of it as 21 MCP tools to any MCP-capable agent (Claude Code, Hermes Agent, …).
Agent ──stdio MCP──> rustdesk-mcp ──> local RustDesk.app ──> remote desktopFeatures
21 tools: session lifecycle, screenshots, hardware-level input injection, a device book, diagnostics (see Tools).
Capture pipeline built for macOS 14+ / 26 — where per-window
CGWindowListCreateImagewas removed: a bundled ScreenCaptureKit helper (tools/rds_capture.swift, source included), a cua-driver daemon fallback, and full-screen-capture + crop as last resort.One coordinate contract:
desktop_*coordinates are pixels on the most recentcontrol_screenshotimage, auto-converted to screen points (Retina included).Device book: persist peers with alias/notes, fuzzy search, discovery from local RustDesk state.
Passwords are accepted per connection call and never written to disk.
Related MCP server: MacWright
How it works
Connect — starts the RustDesk GUI if needed and delivers
rustdesk://connect/<peer>through the--connectCLI. The session window is discovered by title and remembered (survives MCP host restarts).Capture — grabs the session window image, in order:
ScreenCaptureKit helper app (
bin/rds-cap2.app; fast, needs its own Screen Recording grant);cua-driver daemon (optional fallback);
full-screen capture + crop (last resort; slow under LaunchDaemon contexts).
Input — posts hardware-level CGEvents (needs an Accessibility grant for the Python process) at coordinates mapped from the latest screenshot.
Diagnose —
rustdesk_statusreports RustDesk install/version, TCC permission state, and capture-route availability with actionable hints.
Requirements
macOS 14+ (developed and tested on macOS 26, Apple Silicon).
RustDesk desktop client installed and signed in — this server drives your client, so the IDs it can reach are exactly the ones the app can reach.
Python 3.11+.
Xcode Command Line Tools (
swiftc) — only to build the optional capture helper.
Install
git clone https://github.com/Cocos666a/rustdesk-mcp.git rustdesk-mcp
cd rustdesk-mcp
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/pip install -e .
# Optional but recommended — build the fast capture helper:
bash tools/build_helper.sh
./bin/rds-cap2.app/Contents/MacOS/rds-capture --request # grant Screen RecordingPermissions (macOS, one-time)
Full manual: docs/MACOS-PERMISSIONS.md. Summary:
Permission | Who needs it | Why |
Screen Recording | the Python process running this server; the capture helper | screenshot the session window |
Accessibility | the Python process running this server | post keyboard/mouse events |
Accessibility | RustDesk.app | forward your keyboard/mouse to the remote |
Input Monitoring | RustDesk.app | capture your local input on modern macOS — without it, video works but remote input is dead |
Register with your MCP client
Generic stdio config (Claude Desktop, Cursor and other MCP clients):
{
"mcpServers": {
"rustdesk": {
"command": "/absolute/path/to/rustdesk-mcp/bin/rustdesk-mcp"
}
}
}Hermes Agent:
hermes mcp add rustdesk --command /absolute/path/to/rustdesk-mcp/bin/rustdesk-mcpQuick start
With the server registered, a typical agent session calls the tools in this order (real names, real arguments):
rustdesk_status()— RustDesk version, own ID, TCC state, active sessions.session_connect(peer_id="123456789", password="…")— opens a session window and returns itswindow_id+ bounds.control_screenshot()— returns the window image plus its pixel size and scale. That image is the coordinate space for everydesktop_*call.desktop_click_mouse(x=640, y=320)— click at pixel (640, 320) of that image.desktop_typing_text(text="hello")/desktop_typing_keys(keys="cmd+shift+t").session_disconnect(peer_id="123456789")— close the window (the RustDesk process keeps running).
If a screenshot fails, rustdesk_status() tells you which capture route is available and which permission is missing.
Tools
Tool | Purpose |
| Environment + permission diagnostics |
| Session lifecycle (peer id, mode, wait, front, password) |
| Open a port-forward session window |
| Capture the session window (image + geometry meta) |
| Mouse control (image-pixel coordinates) |
| Keyboard control (combos like |
| Sleep (UI settling) |
| Local device book |
peer_id accepts both RustDesk IDs (123456789) and direct IPs (100.x.y.z, LAN IPs) — see docs/TROUBLESHOOTING.md for direct-IP setup on the controlled side.
Runtime state is written to data/ next to the project and is gitignored; the directory is created on first use. It holds devices.json (the device book: peer ids, aliases, notes) and sessions.json (window ids and bounds) — no credentials.
Development
.venv/bin/pytest -q # unit tests
.venv/bin/python tests/smoke_local.py status # local smoke checkSecurity
This server is an input-automation bridge: anything that can call its tools can move the mouse, type, and read the screen of the remote machine. Run it only for an MCP client you trust, and consider a dedicated RustDesk peer instead of your daily-driver machine.
Passwords: accepted per connection call, forwarded to the RustDesk CLI, and never written to disk. They are redacted (
***) in the server's stderr log. Note that therustdesk://URL in the tool result echoes the password you passed, so your MCP host's transcript holds it — treat that transcript as sensitive.Clipboard:
desktop_paste_textwrites to the system clipboard, which overwrites whatever was there, then sends Cmd+V.Device scan: the device book scanner reads only file names under
~/Library/Preferences/com.carriez.RustDesk; it never parses peer configs or password fields.No config writes: the CLI wrapper only passes whitelisted arguments, so it cannot change RustDesk settings (
--set-id,--option,--config, …).
Known limitations
macOS only — implemented against pyobjc/Quartz/CGEvent; no Linux/Windows backend.
No file transfer / command channel yet (Phase 2).
Does not modify RustDesk configuration; it only drives the app.
Public rendezvous reachability depends on your network — some networks (e.g. mainland China) cannot reach RustDesk's public servers; direct IP works fine in that case.
Alternative: driving a Windows host over RDP (tools/winexec)
When macOS refuses to deliver synthetic input (TCC judges the event sender, so a grant for RustDesk.app does not cover the Python process), the GUI path cannot type or click at all. tools/winexec/ sidesteps the macOS input layer: a headless FreeRDP client runs in a Linux container, and keystrokes are injected into its X11 window with xdotool, so they reach the RDP session without touching macOS permissions.
Needs Docker, a Windows host with RDP enabled, and
WIN_HOST/WIN_USER/WIN_PASSin the environment (never written to disk)../winexec.py up→./winexec.py type 'dir C:\' --enter→./winexec.py shot→./winexec.py down.It reconnects your own Windows session, so processes started there survive
down.Details: tools/winexec/README.md.
This is a companion channel, not part of the MCP server — the 21 tools above remain the contract.
Contributing
Issues and pull requests are welcome.
Tool names and arguments are the public contract (
tests/test_tools.pyenforces it) — renaming or unregistering a tool is a breaking change.Run the unit tests before opening a PR:
.venv/bin/pytest -q. They need no TCC permissions and no running RustDesk.Behaviour that only shows up on a real machine (TCC prompts, capture routes, session windows) should be stated with the macOS/RustDesk version you tested on.
License
MIT — see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Connect AI assistants to authorized Windows and macOS devices for files, commands, and management.
Drive real devices from your AI Coding tool. Embed a client SDK (Unity, Godot, Flutter, iOS/macOS, Android, React Native, Web) in your app, then capture screenshots, traverse the UI tree, inject taps and key events, and run automated test tasks on the physical device over a secure relay.
Connect AI assistants to your approved computer for files, commands, browser and desktop tasks.
Use your Mac, Windows or Linux computer from ChatGPT, Claude or Codex: files, commands, documents.
Related MCP Servers
- AlicenseAqualityDmaintenanceProvides native macOS computer control tools including mouse and keyboard simulation, screenshot capture, and application management for MCP-compatible agents. It enables AI assistants to directly interact with the macOS operating system and installed apps through standard tool calls.2444 npm8MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server for reliable native macOS desktop control from AI agents, providing 72 tools for screenshots, mouse, keyboard, scroll, clipboard, window management, and more.MIT
- AlicenseNot gradedqualityDmaintenanceEnables MCP clients to control macOS via accessibility and screen recording, providing tools to list apps, observe UI, click, type, press keys, and scroll.MIT
- AlicenseNot gradedqualityBmaintenanceProvides a JSON-RPC computer use runtime for macOS, exposing 7 MCP tools (observe/act/inspect/session/cancel/trace) as image content blocks so external agents like Claude Code, Pi, OpenCode, or Codex CLI can capture screenshots and drive the desktop with clicks, keys, and typing while enforcing session locking, stale-frame protection, and trace redaction server-side.14 npm1MIT