DesktopBridge
Enables local macOS automation via the Model Context Protocol, allowing file operations, system monitoring, shell commands, clipboard access, and screenshots with configurable security restrictions.
README
DesktopBridge π
Local Model Context Protocol server for macOS. Claude (or any MCP host) talks to it over stdio and can:
- Read, write, list, and search files inside allowlisted directories
- Read CPU / memory / disk stats, uptime, and a redacted environment
- List running applications
- Run shell commands with separate stdout/stderr, timeouts, and optional progress streaming
- Read and write the clipboard
- Capture screenshots and list displays
This process has the same OS rights as the user who launched it. Treat it like giving the model a terminal on your Mac, then shrink that blast radius with DESKTOP_BRIDGE_ROOTS.
Requirements
- macOS (clipboard, screenshots, and application listing use Apple tools)
- Node.js 20.19+ (22 LTS recommended)
Install
cd desktop-bridge
npm install
npm run build
npm test
The compiled entrypoint is dist/index.js.
Connect to Claude Desktop
- Build the server (
npm run build). - Open Claude Desktop β Settings β Developer β Edit Config.
- Merge the block from
claude_desktop_config.example.json, replacing the path and usernames:
{
"mcpServers": {
"desktop-bridge": {
"command": "node",
"args": ["/Users/YOU/dev/desktop-bridge/dist/index.js"],
"env": {
"DESKTOP_BRIDGE_ROOTS": "/Users/YOU/Desktop,/Users/YOU/Documents,/Users/YOU/Downloads"
}
}
}
}
- Fully quit and reopen Claude Desktop.
- Confirm desktop-bridge appears under MCP tools (bridge icon π).
Config file on macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
Connect to Claude Code
claude mcp add desktop-bridge -- node /Users/YOU/dev/desktop-bridge/dist/index.js
Or add the same command / args / env block to ~/.claude.json.
Connect to Cursor
Add to ~/.cursor/mcp.json (or the project .cursor/mcp.json):
{
"mcpServers": {
"desktop-bridge": {
"command": "node",
"args": ["/Users/YOU/dev/desktop-bridge/dist/index.js"]
}
}
}
Smoke-test without a host
npm run inspector
That launches the MCP Inspector against the built stdio server. Call list_roots, then get_system_info.
Logs go to stderr only. Do not console.log in this process β stdout is the JSON-RPC channel.
Environment
| Variable | Default | Meaning |
|---|---|---|
DESKTOP_BRIDGE_ROOTS |
~/Desktop, ~/Documents, ~/Downloads (if they exist) |
Comma-separated directories file tools may touch. The OS temp dir is always added so screenshots have a place to land. |
DESKTOP_BRIDGE_MAX_FILE_BYTES |
10485760 |
Max size for a single file read/write (1 KiBβ100 MiB). |
DESKTOP_BRIDGE_COMMAND_TIMEOUT_MS |
30000 |
Default run_command timeout (100β300000). |
DESKTOP_BRIDGE_MAX_OUTPUT_BYTES |
1048576 |
Combined stdout+stderr capture cap. Excess output kills the process and sets truncated. |
DESKTOP_BRIDGE_ALLOW_SHELL |
true |
Set false to disable run_command. |
DESKTOP_BRIDGE_RESTRICT_SHELL_CWD |
true |
When true, run_command cwd must sit inside an allowed root. |
DESKTOP_BRIDGE_STATUS_URL |
unset | Heartbeat POST URL for the status site (β¦/api/heartbeat). |
DESKTOP_BRIDGE_STATUS_TOKEN |
unset | Bearer token matching the siteβs HEARTBEAT_TOKEN. |
DESKTOP_BRIDGE_STATUS_INTERVAL_MS |
15000 |
Heartbeat interval (5sβ5m). |
Copy .env.example for a commented template. The server reads process env (Claude Desktop env block), not a .env file.
Tools
| Tool | What it does |
|---|---|
list_roots |
Allowed directories and file-size cap |
read_file |
Text (optional line window) or base64 |
write_file |
Create/overwrite/append; optional mkdir -p |
list_directory |
Name, type, size, mtime, mode |
search_files |
Glob on names and/or regex on file contents |
get_system_stats |
CPU %, load, memory, df |
get_system_info |
Host, uptime, user, redacted env |
list_applications |
GUI (or all) processes via System Events |
run_command |
Shell with split stdout/stderr; stream β progress notifications |
read_clipboard / write_clipboard |
pbpaste / pbcopy |
get_display_info |
Display name, main flag, scale, frame |
take_screenshot |
PNG via screencapture; returns an image block when β€ 5 MiB |
Resources: desktop://roots, desktop://system/info.
Prompts: inspect_desktop, find_file.
Security model
- Files: every path is
realpath'd. The resolved path must stay inside a configured root..., extra slashes, and symlinks that escape are rejected. - Home is not a default root. That keeps
~/.sshand similar out of reach until you add them on purpose. - Shell: still a full user shell. A command can
cdanywhere even when cwd is restricted. Disable it withDESKTOP_BRIDGE_ALLOW_SHELL=falseif you only want file/clipboard/screen tools. - Env: keys matching password/token/secret/key/credential/cookie/session are replaced with
[redacted]. - Stdio: no network listener. The host spawns this process.
macOS permissions
| Feature | Permission |
|---|---|
| Screenshots | Screen Recording for the app that spawned Node (Claude Desktop, Cursor, or Terminal) |
list_applications |
Automation β System Events if macOS prompts |
| Accessibility-heavy apps | may still hide titles; the tool lists process names either way |
If screencapture fails, open System Settings β Privacy & Security β Screen Recording and enable the host app, then restart it.
Development
npm run build # tsc β dist/
npm start # node dist/index.js (stdio)
npm test # compile + node:test
Layout: src/lib/* (path guard, process runner, glob/search), src/tools/* (MCP tools), src/index.ts (stdio entry).
Home
https://home.jameymcelveen.com is the browser start page (web/). Widgets are Lit web components under web/public/components/, tagged jm-*. The isolated catalog is Storybook at https://home.jameymcelveen.com/storybook/ (cd web && npm run storybook locally). Lit is vendored into web/public/vendor/ (npm run vendor / postinstall). Sign-in is @mcelveen.us plus STATUS_PASSWORD.
What is there today, and the dump tray for whatever comes next:
| Piece | Notes |
|---|---|
| Widgets | Lit web components, jm-* prefix. Isolated catalog: Storybook |
| Search | Autofocus. Google completions as you type (same suggestion feed as google.com). Kagi / DDG. Bangs: !g !k !d !gh !yt !w !maps |
| Links | Same tiles as the local landing-page app, plus the properties. Edit as JSON in Settings |
| Weather | Open-Meteo, Β°F, Florence SC unless you override coords |
| Mac | DesktopBridge heartbeat: online / stale / offline, IPs, load |
| VIN Sweep | Client-side NHTSA decode / recalls / complaints, plus human-only NICB / FL title / iSeeCars taps |
| Scratch | Autosaved notes |
| Word | Daily verse |
Set Chrome/Safari/Firefox homepage to https://home.jameymcelveen.com (browsers will not let the page do it for you). Session cookie lasts 30 days. / focuses search; βK too.
Push to main runs CI, then deploys Vercel (the site) and Railway (heartbeat + saved config).
On the Mac, add to the MCP server env:
DESKTOP_BRIDGE_STATUS_URL=https://home.jameymcelveen.com/api/heartbeat
DESKTOP_BRIDGE_STATUS_TOKEN=<HEARTBEAT_TOKEN>
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.