A native RDP server for macOS, written in Rust on top of IronRDP. Connect from mstsc, the Windows App / Microsoft Remote Desktop, or FreeRDP and drive your Mac — authenticated against your local Mac account (NLA/CredSSP, TLS). What you get:
- Desktop: H.264 video (hardware-encoded, opt-in, with optional adaptive bitrate) or legacy bitmaps; keyboard (non-US layouts auto-detected) and mouse with the real cursor shape; the session follows your client's resolution.
- Clipboard & files: text, images and rich text both ways; copy files and folders between Mac and Windows.
- Audio: Mac audio to the client; the client's microphone as a real Mac input device (experimental).
- Devices from the client: drives mounted in Finder (read-write), smart cards for macOS apps, the webcam as a real Mac camera, and USB devices (experimental).
- Headless: serve a virtual display so the Mac needs no monitor, with the physical screen blanked while you're connected.
This is the macOS equivalent of xrdp. Not a client, not a VNC bridge.
v0 — daily-driver usable on a trusted LAN and over a VPN (ZeroTier, high-latency and mobile links included). Scope and limits: Production readiness.
Latest: v0.9.10 — microphone redirection (experimental): the client's mic appears on the Mac as "macrdp Microphone", usable in Zoom, Teams or QuickTime. Also fixes --lock-on-disconnect locking underneath a client that is still reconnecting.
Recent releases
- v0.9.9 (2026-09-29) — rich-text clipboard in both directions
- v0.9.8 (2026-09-27) — lock while away:
--lock-on-disconnect+--auto-unlock(experimental) - v0.9.7 (2026-09-19) — security patch: rustls, cryptoki and h2 advisories
- v0.9.6 (2026-08-16) — fixes a scroll-down regression and an unauthenticated denial of service
- v0.9.5 (2026-08-06) — IronRDP update; two vendored forks retired
- v0.9.4 (2026-08-05) — security hotfix for a pre-TLS denial of service
- v0.9.3 (2026-07-29) — a second client takes over the session; blank-recovery storm-guard fix
- v0.9.2 (2026-07-26) — blank recovery no longer drops a session that is working
- v0.9.1 (2026-07-23) —
--shield-primary: headless and still lockable - v0.9.0 (2026-07-20) — the client's webcam as a real Mac camera
Full per-release notes (what shipped, what was verified live, and the war stories): docs/release-history.md.
Short version: production-ready for single-user use on a LAN or VPN — soak-tested past 48 h twice with no leaks or panics, hardened, and abuse-tested. Not an enterprise RDP server: one session at a time, a solo project with no SLA, and features marked experimental (for example USB, microphone, lock-on-disconnect/auto-unlock) haven't been soak-tested. Never expose it — or any RDP server — on a public IP; reach it over a VPN or RD Gateway.
Solid (verified on real mstsc / Microsoft Remote Desktop / FreeRDP): TLS + NLA/CredSSP auth against your Mac account (Keychain-backed, real CA certs supported, per-IP rate-limiting + lockout + audit log); the full daily workflow (display, input incl. non-US layouts, clipboard/files both ways, audio, drive + smart-card redirection, headless virtual displays); H.264 with congestion-responsive rate control that degrades gracefully instead of freezing; signed/notarized packaging with a LaunchAgent, menu-bar controller, and a health-check watchdog; soak-tested past 48 h twice (v0.9.3, v0.9.6; no leaks, 0 panics) and abuse-tested; 250+ tests in CI.
Know before relying on it: single session/single user; no multi-monitor or printer redirection; DRM video and password-manager windows capture black (macOS policy, not fixable); synthetic input can't reach the login window/secure fields (same); reconnecting mstsc can briefly show a blank screen (client quirk — the server now auto-heals it in ~4 s by reactivating the RDP core in place, no user action); the UDP paths are opt-in and newer than the TCP core; it's a solo v0 on vendored IronRDP forks, no SLA. Never expose any RDP server on a raw public IP — reach it over a VPN or RD Gateway.
Details and the path to closing the gaps: docs/production-readiness-roadmap.md.
cargo build --release
codesign -s - --force target/release/macrdp # ad-hoc sign so TCC grants persist
./target/release/macrdpFirst run will prompt for:
- Screen Recording permission (System Settings → Privacy & Security → Screen Recording → enable
macrdp→ restart it). - Accessibility permission (same path, "Accessibility" — required to forward keyboard and mouse).
- Your Mac password at the terminal — validated against your local account via PAM
checkpw, then used as the RDP credential.
Then connect from a client to <your-mac-ip>:3390 with your Mac username and password. mstsc will prompt for credentials in its own NLA dialog — no need to pre-type the username.
Common flags to try next (full reference: docs/configuration.md):
./macrdp --enable-h264 # H.264 video — crisper AND lighter than the default bitmaps
./macrdp --enable-h264 --adaptive-bitrate # + congestion-responsive rate control (recommended off-LAN)
./macrdp --bind 0.0.0.0:3390 # accept LAN connections (keep it OFF public IPs)
./macrdp --virtual-display --width 2560 --height 1440 # headless second desktop; local screen untouched
./macrdp --map-ctrl-to-cmd # Windows Ctrl+C/V/X muscle memory drives macOS copy/pastemacrdp reimplements the macOS symbolic hotkeys in user space (WindowServer won't fire them for forwarded events). On a Windows client the Cmd key is the Windows key, so press the Win-key equivalent:
| Keys (on the client) | Action |
|---|---|
| Cmd+Tab / Cmd+Shift+Tab | Cycle apps (forward / back); the app you land on is surfaced |
| Cmd+` / Cmd+Shift+` | Cycle windows of the current app |
| Cmd+Space | Spotlight |
| Cmd+Shift+3 / 4 / 5 | Screenshots (full screen / region / Screenshot.app) |
| Ctrl+Alt+G | Gather windows stranded off the virtual display (headless --capture-primary/--detach-primary modes) |
| Ctrl+Alt+Shift+R | On-demand A/V resync — repaint a stale/idle-blanked screen (forced keyframe) and re-sync drifted audio, without disconnecting. Handy for mstsc after hours idle. |
Optional flags: --alt-tab-switch / --alt-backtick-switch accept Option+Tab / Option+` as the same triggers; --app-switcher-hud draws a visible switcher overlay; --map-ctrl-to-cmd remaps Windows Ctrl+C/V/X/… editing shortcuts to their Cmd equivalents.
mstsc tip: if Cmd+Tab seems ignored, set Local Resources → Keyboard → "Apply Windows key combinations" to "On the remote computer" (or go full-screen) — the windowed default eats Win+Tab locally as Task View.
dist/install.shBuilds + signs + installs to ~/.local/bin/macrdp, stores your Mac password in the macOS Keychain under service macrdp, drops a launchd plist at ~/Library/LaunchAgents/com.user.macrdp.plist, and loads it. macrdp will start on every login and restart if it crashes. Re-run the script after cargo build --release to refresh the installed binary.
launchctl print gui/$UID/com.user.macrdp | head # status
launchctl kickstart -k gui/$UID/com.user.macrdp # restart
launchctl bootout gui/$UID/com.user.macrdp # stop / uninstalldist/install.sh installs a bare binary. For a proper signed macrdp.app — stable bundle identity (TCC grants survive rebuilds), background-agent behavior, the embedded smart-card IFD handler, optional notarization, the menu-bar controller app, and a distributable DMG:
packaging/make-app.sh # build + sign + install to /Applications
security add-generic-password -s macrdp -a "$(id -un)" -w 'YOUR_PASSWORD'
packaging/install-launchagent.sh # load LaunchAgent (label com.clintcan.macrdp)Feature toggles, bind address, and extra flags live in ~/Library/Application Support/macrdp/config.env — outside the bundle, so edits never disturb the signature or TCC grants. The full packaging guide (Developer-ID signing, notarization, the DMG, the controller app, icons, TCC notes): packaging/README.md.
Pushing a v* tag runs the release workflow, which builds on an Apple-Silicon runner and attaches these to a draft GitHub Release (Apple Silicon / aarch64-apple-darwin only):
| File | What it is |
|---|---|
macrdp-<ver>-aarch64-apple-darwin.tar.gz |
the bare CLI binary + LICENSE/README |
macrdp-<ver>-aarch64-apple-darwin-app.zip |
the full macrdp.app, with the embedded smart-card IFD handler + installer — the only artifact that carries everything --enable-smartcard-redirection needs |
SHA256SUMS |
checksums for both |
Both are ad-hoc signed, not notarized — open the app once via right-click → Open (or xattr -dr com.apple.quarantine macrdp.app). For a Developer-ID-signed + notarized build, or the menu-bar controller app (neither is produced in CI), build locally with packaging/make-app.sh.
| Guide | What's in it |
|---|---|
| Configuration & CLI | Every flag, the auth-hardening environment variables (rate-limit/lockout/audit), headless mode (--virtual-display, --detach-primary/--capture-primary), and a full set of example invocations. |
| Video | The H.264/EGFX pipeline, Retina capture (--hidpi), client-resolution auto-adopt and letterboxing, bitrate/keyframe tuning, the mstsc reconnect-blank quirk and its in-place auto-recovery, and the vImage color-conversion benchmarks. |
| Audio | RDPSND PCM, opt-in AAC compression (--enable-aac), the self-healing capture stream, mute-on-minimize — and the experimental microphone redirection (--enable-microphone-redirection): the client's mic as a real macOS input device. |
| File copy | Mac↔Windows clipboard file copy (files and folder trees), lazy vs eager paste, and the two Windows-side gotchas (Explorer folder-copy, archive shell extensions). |
| Drive redirection | Mounting the client's drives as read-write Finder volumes (--enable-drive-redirection) — how the in-process NFS bridge works and what to expect from permissions. |
| Camera redirection | Presenting the client's webcam as a real macOS camera (--enable-camera-redirection) — the one-time system-extension setup and activation, how the MS-RDPECAM → VideoToolbox → CoreMediaIO pipeline fits together, and the four CoreMediaIO failure modes that all fail silently. For a webcam use this, not USB redirection — it's the path mstsc feeds. |
| Smart-card redirection | Using the client's smart card from macOS apps (--enable-smartcard-redirection) — one-time IFD-handler install, the USB-trigger caveat, upgrade/reload notes, and why it's a user-space handler rather than USB passthrough. |
| Audit log & SIEM | The security audit events (accept / reject / auth / disconnect) — every field and how to interpret them — plus forwarding the JSON stream to a SIEM/SOC collector (Vector / Fluent Bit / rsyslog) and a runnable OpenSearch SIEM tutorial that detects an RDP brute-force end-to-end. |
| vs. other OSS RDP servers | Two parts. Part 1 — the evidence behind every "first" claim in these docs, verified adversarially against FreeRDP/xrdp and re-checked in the source, including what macrdp is not first at and how to re-verify when upstreams move. Part 2 — an honest head-to-head against the other native macOS RDP servers (x6nux/macrdp, RDPonMAC), written steelmanning theirs, including where they beat us. |
| Release history | Per-release narrative of what shipped and what was live-verified. |
| CLAUDE.md | Developer/agent index — current release, plus pointers to the feature list, architecture, macOS gotchas and known quirks. |
This was done to scratch an itch. There are practically no active open source RDP servers for macOS. The closest project with this functionality is xrdp; however it only runs on Linux/Unix machines and has no homebrew equivalent on Macs. The initial POC was done in a few hours with the help of Claude and ran pretty well from the start. Additional combing through pcap files and documentation, and debugging each mstsc/FreeRDP connect, is what makes this work tedious yet rewarding when it finally works. Multi-monitor support is on the list for when I'm bored or need a distraction from real life.
macrdp is free and open source. If it's helped you out, you can buy me a coffee to help me get through the bumps — totally optional, no pressure.
Licensed under either of MIT or Apache-2.0 at your option. Being permissively licensed, a productized/notarized build may be sold commercially with support — that's selling the product, not a license exemption.