Enables comprehensive remote control of macOS systems, allowing AI agents to execute shell commands, manage files and directories, and perform UI automation through AppleScript.
Provides the capability to execute asynchronous Zsh commands on a remote Mac, returning standard output, standard error, and exit codes for system interaction and automation.
Click on "Install 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., "@remote-control-mcpOpen Maps, find a coffee shop nearby, and take a screenshot"
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.
remote-control-mcp
An MCP server that gives AI services (Claude, Cursor, etc.) remote control of your Mac — execute shell commands, read/write files, and run AppleScript — secured with OAuth 2.0 + PKCE.
Demo

Claude searches for a tteok shop on Naver Maps, gets driving directions, takes a screenshot, and emails the result. All done in the Claude app on iOS.
What it does
Exposes your Mac as an MCP server reachable over the internet through a secure tunnel
Runs shell commands (
zsh) asynchronously and returns stdout, stderr, and exit codeReads and writes files and directories using
fs.promises— no shell injection surfaceExecutes AppleScript for UI automation and app control
Protects every tool call with OAuth 2.0 + PKCE; token rotation revokes old tokens immediately
Optional file server (port 3835) to share files from
~/Public/mcp-files/via browser or any HTTP client
⚠️ Security Warning
This server provides remote shell execution on your Mac.
OAuth 2.0 + PKCE protects the MCP endpoint — valid tokens are required for all tool calls
PIN-gated authorization — connecting a new client requires a one-time PIN generated by
rcmcp authon your local machine. The PIN is never written to disk and is only accessible via localhost. Anyone who reaches/authorizewithout the PIN cannot obtain a token.The network layer is your second line of defense — always expose the server through an authenticated tunnel. Never bind directly to a public IP.
This server is designed for personal, single-user use behind a private tunnel. Do not expose it to untrusted networks.
Requirements
macOS (Linux support planned; AppleScript tools are macOS-only)
Node.js
>=20.16.0or>=22.3.0A tunnel to expose the server — Cloudflare Tunnel, ngrok, or Tailscale (see below)
Redis (required in production for token persistence; in-memory fallback used without it)
Quick Start
Automated (recommended)
setup.sh handles everything interactively — dependencies, .env, build, tunnel, LaunchAgent, and CLI:
git clone https://github.com/hexpy-games/remote-control-mcp
cd remote-control-mcp
./setup.shManual
git clone https://github.com/hexpy-games/remote-control-mcp
cd remote-control-mcp
npm install
cp .env.example .env
# Edit .env — set BASE_URI to your tunnel URL
npm run build
npm startThen set up a tunnel (see below) and add the server URL to your AI client.
Tunnel Options
Never bind the server directly to a public IP. Use one of the following:
setup.sh(Cloudflare Tunnel and ngrok). Tailscale and direct IP require manual setup.
Option 1: Cloudflare Tunnel (recommended — free, stable URL)
setup.sh handles installation, authentication, DNS routing, and LaunchAgent registration automatically.
To set up manually:
brew install cloudflared
# Permanent subdomain (requires free Cloudflare account)
cloudflared tunnel login
cloudflared tunnel create remote-control-mcp
cloudflared tunnel route dns remote-control-mcp your-subdomain.yourdomain.com
# Set BASE_URI=https://your-subdomain.yourdomain.com in .env
cloudflared tunnel run remote-control-mcpOne-shot (URL changes each run, useful for testing):
cloudflared tunnel --url http://localhost:3232Option 2: ngrok (quick setup, generous free tier)
setup.sh handles installation, authtoken, and LaunchAgent registration automatically.
To set up manually:
brew install ngrok
ngrok config add-authtoken <your-token>
ngrok http 3232
# Copy the https URL and set it as BASE_URI in .envThe ngrok free tier assigns a random URL on each restart — update
BASE_URIin.envafter each restart, then runrcmcp restart server. Paid plans support a fixed static domain.
Option 3: Tailscale Funnel (manual setup only)
Tailscale is not yet supported by setup.sh. Set up manually:
brew install tailscale
tailscale up
tailscale funnel 3232
# Copy the https://...ts.net URL shown and set it as BASE_URI in .envTailscale Funnel gives you a stable *.ts.net HTTPS URL with no account beyond a free Tailscale plan.
Option 4: Direct IP (advanced, manual only)
Only use this if you understand the risks and have proper TLS termination in place:
Forward port 3232 on your router to your Mac
Set
BASE_URIto your domain or public IP in.envTerminate TLS at a reverse proxy — plain HTTP exposes OAuth tokens in transit
# Example: Caddy as a TLS-terminating reverse proxy
brew install caddy
# Caddyfile:
# your-domain.com {
# reverse_proxy localhost:3232
# }
caddy runConnect to Claude
After the server is running and a tunnel is up:
1. Add the MCP server in Claude
In Claude.ai (desktop or web): go to Settings → Integrations → Add Integration and paste your server URL:
https://your-tunnel-url/mcpClaude will immediately start an OAuth authorization flow.
2. Authorization
A browser window will open asking you to approve the connection. This is where you enter the Server PIN.
Get your PIN:
rcmcp authThis generates a fresh one-time PIN, copies it to your clipboard, and waits for you to complete the authorization:
Authorization PIN
────────────────────────────────────────
9aRs-VhzM (copied to clipboard)
→ Enter this PIN on the /authorize approval page.
⠙ Waiting for authorization...Paste the PIN into the browser form and click Approve. The terminal will confirm automatically:
✓ Authorization complete3. Start using remote tools
Once authorized, Claude has access to four tools on your Mac:
Tool | What it does |
| Run any zsh command |
| Run AppleScript (UI automation, app control) |
| Read files or list directories |
| Write files (creates directories as needed) |
Example prompts to try:
"Take a screenshot and describe what's on my screen"
"What files are in my Downloads folder?"
"Search for coffee shops near me on Maps and send me the directions"
Other clients: Any MCP-compatible client (Cursor, Windsurf, etc.) can connect using the same server URL. The OAuth flow is standard.
Configuration
Copy .env.example to .env and edit as needed.
Variable | Default | Description |
|
| Port the MCP server listens on |
|
| Public URL of this server — must match your tunnel URL |
|
| Set to |
| (empty) | Comma-separated substrings to block in |
| (unset) | Redis connection URL — required in production |
|
| Set to |
Redis
Redis is required in production for token persistence and expiry. Without it, tokens are stored in memory and lost on restart.
# Docker
docker run -d -p 6379:6379 redis:7-alpine
# Homebrew
brew install redis && brew services start redisSet REDIS_URL=redis://localhost:6379 in .env.
Available Tools
Tool | Description |
| Execute a |
| Execute an AppleScript. Scripts are written to a private temp directory to prevent TOCTOU races. Use for UI automation and app control. |
| Read file contents or list a directory. Uses |
| Write content to a file. Creates intermediate directories if needed. |
Security notes
BLOCKED_COMMANDSis a last-resort safeguard, not a security boundary. Security is enforced at the OAuth + tunnel layer.Refresh token rotation revokes the previous token immediately.
A default blocklist prevents the most catastrophic commands (
rm -rf /, fork bombs, direct disk writes, etc.).
rcmcp CLI
setup.sh installs rcmcp, a management CLI for day-to-day operations:
rcmcp status # server + tunnel + file server status and endpoint URL
rcmcp start [server|tunnel|fileserver|all]
rcmcp stop [server|tunnel|fileserver|all]
rcmcp restart [server|tunnel|fileserver|all]
rcmcp logs [server|tunnel|fileserver|all] [-f]
rcmcp url # print current MCP endpoint URL
rcmcp update # git pull → rebuild → restart server
rcmcp uninstall # remove LaunchAgents, binary, and PATH entryTargets can be abbreviated: srv, tun, fs.
File Server (optional)
setup.sh can install an optional lightweight file server (port 3835) that serves files from ~/Public/mcp-files/ over HTTP. Useful for sharing or viewing Mac files from any browser, HTTP client, or AI service.
GET https://your-tunnel-url/files/<filename>Managed via rcmcp start fileserver / rcmcp stop fileserver.
Development
# Run with live reload
npm run dev
# Type-check without emitting
npm run typecheck
# Lint
npm run lint
# Build
npm run buildContributing
Reporting issues
Bug: Open an issue with the prefix
[bug]. Include OS version, Node version, reproduction steps, and expected vs. actual behavior.Feature request: Open an issue with the prefix
[feat]. Describe the use case, not just the solution.
Submitting a PR
Fork the repo and create a branch from
mainFollow branch naming conventions:
feat/— new featurefix/— bug fixdocs/— documentation onlychore/— tooling, deps, CI
Run
npm run lintandnpm run typecheck— both must passOpen a PR against
mainwith a clear description of what and why
Commit style
Use Conventional Commits:
feat: add Tailscale tunnel option
fix: prevent shell_exec hanging on commands with no output
docs: clarify Redis requirement in README
chore: upgrade MCP SDK to 1.25What gets accepted
Security improvements
New MCP tools that fit the "remote Mac control" scope
Additional tunnel provider support
Bug fixes
What gets rejected
Changes that remove the OAuth requirement
Features that broaden scope to multi-user or server-side use cases
License
MIT — Copyright (c) 2026 Hexpy Games & remote-control-mcp contributors
See LICENSE for the full text.
Disclaimer
This project is not affiliated with, endorsed by, or sponsored by Anthropic, Claude.ai, or any other AI service provider.
This server cannot be installed
Resources
Looking for Admin?
Admins can modify the Dockerfile, update the server description, and track usage metrics. If you are the server author, to access the admin panel.