hammerspoon-mcp
Enables Bluetooth device management, including listing paired or connected devices, connecting/disconnecting by name or MAC address, and controlling power state.
Provides deep control over macOS, including window management, Spaces, audio devices, Bluetooth, Focus mode, system state, and access to 200+ OS-level APIs.
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., "@hammerspoon-mcpMove the current window to the right half of the screen"
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.
hammerspoon-mcp
Give AI agents deep control over macOS — windows, audio, Bluetooth, Spaces, Focus mode, and 200+ OS APIs — through one MCP server.
What is this?
An MCP server that bridges AI agents to Hammerspoon — the most powerful macOS automation tool available. Unlike screenshot-and-click tools, this gives agents programmatic OS-level access: manage windows by ID, switch audio devices by name, move apps between Spaces, toggle Focus mode, and subscribe to real-time OS events.
75 tools. 12 subscribable resources. Zero native dependencies.
Related MCP server: computer-use
Quick Start
# 1. Install Hammerspoon (if you haven't)
brew install --cask hammerspoon
# 2. Enable the IPC module (one-time setup)
# Add this line to ~/.hammerspoon/init.lua:
# require("hs.ipc")
# Then reload your Hammerspoon config (Cmd+Alt+Ctrl+R or restart the app)
# 3. (Optional) Install the hs CLI symlink for convenience:
# Run in Hammerspoon console: hs.ipc.cliInstall()
# Or manually: ln -sf /Applications/Hammerspoon.app/Contents/Frameworks/hs/hs ~/.local/bin/hs
# 4. Run the MCP server
npx hammerspoon-mcpNote: The server auto-discovers the
hsbinary — it checks~/.local/bin/hs,/usr/local/bin/hs,/opt/homebrew/bin/hs, and the app bundle path. You don't needhson your PATH if Hammerspoon is installed to/Applications.
Architecture
┌─────────────────────────────────────────────────────────┐
│ MCP Client (Claude, Cursor, MeshClaw, etc.) │
└──────────────────────────┬──────────────────────────────┘
│ stdio (JSON-RPC)
┌──────────────────────────▼──────────────────────────────┐
│ hammerspoon-mcp (Node.js) │
│ ├─ tools → execSync("hs -c '...'") (request/response)│
│ └─ watchers → named pipe reader (push events) │
└──────────────────────────┬──────────────────────────────┘
│ hs CLI / named pipe
┌──────────────────────────▼──────────────────────────────┐
│ Hammerspoon.app (Lua runtime + ObjC bridge) │
│ 200+ modules: window, screen, spaces, audio, wifi, │
│ bluetooth, battery, USB, filesystem, accessibility... │
└──────────────────────────┬──────────────────────────────┘
│
macOS APIs (CoreGraphics, IOKit, etc.)MCP Client Configuration
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"hammerspoon": {
"command": "npx",
"args": ["hammerspoon-mcp"]
}
}
}claude mcp add hammerspoon -- npx hammerspoon-mcpAdd to .vscode/mcp.json:
{
"servers": {
"hammerspoon": {
"command": "npx",
"args": ["hammerspoon-mcp"]
}
}
}Add to ~/.aws/amazonq/mcp.json:
{
"mcpServers": {
"hammerspoon": {
"command": "npx",
"args": ["hammerspoon-mcp"]
}
}
}Tools
🪟 Window Management (7)
Tool | Description |
| All visible windows with app, title, frame, id |
| Bring window to front by id or title match |
| Move/resize window by id |
| 16 presets (halves, thirds, quarters, grid, cascade, center…) + custom fractional layouts |
| Snapshot all window positions as a named layout |
| Restore a saved layout (matches by app + title) |
| List saved layout names |
🖥️ Spaces / Virtual Desktops (9)
Tool | Description |
| All spaces per screen with active markers |
| Currently focused space + screen |
| Switch by ID or index |
| Move window to another space (optionally follow) |
| Create a new space |
| Remove a space (safety checks) |
| Windows on a specific space |
| Which space(s) a window is on |
| Toggle Mission Control / Exposé / Launchpad / Show Desktop |
📱 Application Control (3)
Tool | Description |
| Running applications with bundle ID, PID, hidden state |
| Launch or activate an app by name |
| Quit an app |
⌨️ Input (3)
Tool | Description |
| Click at coordinates with button + modifier options |
| Type text (Unicode, CJK, emoji) |
| Press key combo (e.g. |
🖼️ Screen (3)
Tool | Description |
| Capture full screen or region (base64 PNG) |
| Display info (resolution, name, rotation) |
| Current cursor coordinates |
🔊 Audio Devices (6)
Tool | Description |
| List all input/output with volume, mute, transport type |
| Get/set default devices (fuzzy name match) |
| Volume on any specific device (0–100) |
| Mute/unmute/toggle any device |
| List/switch data sources (speakers vs headphones) |
| Watch for device changes |
🔵 Bluetooth (5)
Tool | Description |
| Power state and discoverability |
| On / off / toggle |
| List paired or connected devices |
| Connect by name (fuzzy) or MAC address |
| Disconnect a device |
Requires blueutil:
brew install blueutil
🌙 Focus / Do Not Disturb (6)
Tool | Description |
| Check if DND/Focus is active + profile name |
| Toggle via Control Center (no setup needed) |
| Enable/disable via macOS Shortcuts (most reliable) |
| One-time setup guide |
| DND for N minutes with auto-disable |
| Cancel scheduled disable |
🔋 System State (6)
Tool | Description |
| Charge %, power source, time remaining |
| Current SSID and interface details |
| System volume get/set |
| Get/toggle dark mode |
| Post a macOS notification |
| Read/write system pasteboard |
🔆 Display (1)
Tool | Description |
| Get/set screen brightness (0–100) |
⏱️ Timers (3)
Tool | Description |
| Named countdown with notification on fire |
| Cancel by name |
| List active timers |
📁 Finder / Files (4)
Tool | Description |
| Get currently selected Finder items |
| Open/reveal path in Finder |
| Move to Trash (reversible) |
| Quick Look preview |
🛠️ Utilities (5)
Tool | Description |
| CPU, memory, thermal state, uptime |
| Prevent sleep for N minutes |
| Run shell command (user environment) |
| Open URL in browser or specific app |
| HUD-style on-screen overlay message |
👁️ Watchers — Live OS Event Streams (13)
Tool | Events |
| App activated, launched, terminated, hidden |
| Network changes |
| Device connect/disconnect |
| Charge level, power source |
| Display configuration |
| Filesystem changes |
| Sleep/wake/lock/unlock |
| Every pasteboard change |
| Ring buffer with source app tracking |
| Read the full buffer |
| Incoming |
| Stop a watcher |
| List active watchers |
🧪 Escape Hatch (1)
Tool | Description |
| Execute arbitrary Lua in the Hammerspoon runtime |
This gives access to all 200+ Hammerspoon modules not covered by dedicated tools — USB details, serial ports, network interfaces, Canvas drawing, menubar items, etc.
Resources (Subscriptions)
MCP clients can subscribe to resource URIs and receive push notifications when OS events fire:
URI | Triggers |
| App lifecycle events |
| Network changes |
| USB device events |
| Battery/power changes |
| Display reconfiguration |
| Filesystem changes |
| Sleep/wake/lock events |
| Pasteboard changes |
| Clipboard ring buffer updates |
| Incoming URL events |
| Audio device changes |
| System info snapshot |
How event streaming works
Agent calls: hs_watch_wifi
→ Server injects Lua watcher into Hammerspoon runtime
→ macOS WiFi change fires
→ Watcher writes JSON to named pipe (/tmp/hs-mcp-events.pipe)
→ Node reader emits event
→ Server calls sendResourceUpdated("watcher://wifi")
→ Client reads resource → gets { ssid: "NewNetwork", ... }Examples
"Tile my editor and terminal side by side"
hs_window_layout({ preset: "side-by-side" })"Switch my audio to AirPods"
hs_audio_default({ output: "airpods" })
→ "set default output: AirPods Pro""Move Slack to Space 3"
hs_list_windows({ app: "Slack" }) → { id: 4523, ... }
hs_spaces_move_window({ windowId: 4523, spaceIndex: 3 })"Start a 25-minute focus session"
hs_focus_schedule({ minutes: 25 })
hs_timer_start({ name: "pomodoro", minutes: 25, message: "Break time!" })"Notify me when I switch away from my IDE"
hs_watch_apps()
→ Events stream to watcher://apps whenever focus changes"Connect my headphones and set volume to 40%"
hs_bluetooth_connect({ device: "WH-1000XM5" })
hs_audio_volume({ device: "WH-1000XM5", volume: 40 })Compared to Alternatives
Capability | hammerspoon-mcp | mac-use-mcp | macos-automator-mcp |
Window management by ID | ✅ | ❌ | ❌ |
Virtual desktop (Spaces) control | ✅ | ❌ | ❌ |
Audio device switching | ✅ | ❌ | ❌ |
Bluetooth control | ✅ | ❌ | ❌ |
Focus / DND mode | ✅ | ❌ | ❌ |
Real-time OS event subscriptions | ✅ | ❌ | ❌ |
Clipboard history | ✅ | ✅ | ❌ |
Arbitrary OS scripting | ✅ (Lua) | ❌ | ✅ (AppleScript) |
Screenshot | ✅ | ✅ | ❌ |
Click / type / hotkeys | ✅ | ✅ | ❌ |
Accessibility tree queries | via | ✅ | ❌ |
Zero-install (no prerequisites) | ❌ | ✅ | ✅ |
Total tools | 75 | 18 | ~10 |
Prerequisites
Requirement | Install |
macOS 13+ | — |
Node.js 22+ |
|
Hammerspoon |
|
| Add |
blueutil (optional) |
|
The
hsCLI symlink (hs.ipc.cliInstall()) is optional — the server auto-discovers the binary inside the Hammerspoon app bundle.
Verify setup
# If hs is on your PATH:
hs -c 'return "ok"'
# Or directly via the app bundle:
/Applications/Hammerspoon.app/Contents/Frameworks/hs/hs -c 'return "ok"'
# Should print: okIf this works, npx hammerspoon-mcp will connect successfully.
Permissions
Permission | Required for | How to grant |
Accessibility | Window, input, app control | System Settings → Privacy & Security → Accessibility → add your terminal |
Screen Recording |
| System Settings → Privacy & Security → Screen Recording |
Project Structure
hammerspoon-mcp/
├── src/
│ ├── index.ts MCP server entry point + resource registration
│ ├── bridge.ts hs CLI bridge (auto-discovers binary, eval, evalJson)
│ ├── tools.ts Core tools: window, app, input, screen, system, eval (23)
│ ├── watcher-tools.ts Watcher management tools (13)
│ ├── watchers.ts Named pipe event bridge
│ ├── spaces-tools.ts Spaces / virtual desktop tools (9)
│ ├── audio-tools.ts Audio device management (6)
│ ├── focus-tools.ts DND / Focus mode (6)
│ ├── bluetooth-tools.ts Bluetooth via blueutil (5)
│ └── extra-tools.ts Brightness, timers, system info, Finder, utils (13)
├── package.json
├── tsconfig.json
├── LICENSE MIT
└── README.mdDevelopment
git clone <repo>
cd hammerspoon-mcp
npm install
npm run dev # Run with tsx (hot reload)
npm run build # Compile to dist/
npm start # Run compiled versionHow It Works
Startup — the bridge auto-discovers the
hsbinary (checks~/.local/bin,/usr/local/bin,/opt/homebrew/bin, app bundle) and validates connectivityTools execute synchronously via
hs -c '<lua>'— typically 30–80ms per call. Stdout noise (-- Loading extension: ...) is stripped automaticallyWatchers inject Lua code that writes JSON lines to a FIFO pipe; a Node reader process emits them as MCP resource updates
Resources buffer the last 50 events per watcher; clients read on-demand after receiving update notifications
Graceful shutdown stops all watchers and cleans up the pipe on SIGINT/SIGTERM
Known Limitations
Node.js 22+ is specified in
enginesbut the server builds and runs fine on Node 20 (tested)hs_spaces_goto,addSpaceToScreen,removeSpacebriefly flash Mission Control (macOS limitation — enable "Reduce motion" to minimize)Bluetooth tools require blueutil (
brew install blueutil)Focus/DND reading uses heuristics (no public Apple API exists)
hs_screenshotreturns base64 — large for full-screen capturesSaved layouts persist only in Hammerspoon's runtime (lost on HS reload)
Named pipe path is
/tmp/hs-mcp-events.pipe— only one server instance at a time
License
MIT © 2026 Mohammed Babur
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityAmaintenanceA lightweight MCP server that bridges AI agents and macOS, enabling automation of file navigation, application control, UI interaction, browser automation, and system operations.145MIT
- Alicense-qualityCmaintenanceStandalone MCP server that gives AI agents full GUI control over macOS — screenshots, mouse, keyboard, apps, clipboard, and multi-display — with zero private dependencies.16MIT
- Alicense-qualityBmaintenanceA local macOS MCP server for AI Agents that exposes safe endpoints for shell commands, files, processes, macOS automation, browser control, and more.2MIT
- Alicense-qualityDmaintenanceMCP server that enables AI to fully control macOS — mouse, keyboard, terminal, screenshots, window management, UI element detection, and provides AI-optimized information reporting.32MIT
Related MCP Connectors
Let ChatGPT, Claude & Cursor use your Mac: email, calendar, iMessage, Teams, files. Local, free.
User-owned memory for AI agents, Copilot, Claude, IDEs, CLIs, and chat apps over remote MCP.
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yo…
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/mobabur94/hammerspoon-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server