Control macOS through Hammerspoon: windows, apps, and API search. Injection-safe by design.
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent โ or use 1-click editor setup below.
๐ก Paste the JSON block into your client's configuration file under mcpServers, then restart the application.
Let an AI agent drive your Mac through Hammerspoon, without ever splicing its input into Lua source.
Hammerspoon is a macOS automation app you script
in Lua. It exposes a command line interface through its hs.ipc module, so
hs -c "<lua>" runs Lua inside the running Hammerspoon process.
This project is an MCP (Model Context Protocol) server that sits in front of that CLI. It gives an agent a set of typed tools (list windows, move a window, focus an app, search the Hammerspoon API docs, tail the console, reload your config) and translates each tool call into a Lua program that Hammerspoon runs.
It speaks MCP over stdio, so any MCP client can use it: Claude Code, Claude Desktop, or your own.
Published on npm as v0.4.x: 38 safe-tier tools, plus 3 gated behind
HS_MCP_TOOLS=all. Still pre-1.0, so tool names and argument shapes can
change between minor versions.
Most of the risk in a "run Lua for me" bridge is the moment you build the Lua. The usual approach is to interpolate the arguments into a source string and escape the dangerous characters. Escaping is a discipline, and disciplines slip.
This server never interpolates. Every tool's Lua body is a static constant in the TypeScript source. Arguments travel separately:
The tool body then reads ARGS.title, ARGS.windowId, and so on.
The base64 alphabet is A-Z, a-z, 0-9, +, /, and =. It contains no
quote, no backslash, no newline, no square bracket, and no hyphen. So the
payload cannot close the Lua string, cannot start an escape sequence, cannot
open a long bracket, and cannot open a comment. Injection is impossible because
of the alphabet, not because someone remembered to escape correctly.
There is no shell layer either. The server talks to Hammerspoon over a
persistent Unix socket, falling back to spawn(hsPath, ["-c", lua]) with an
argv array, so no sh ever parses the command on either path.
The default tier is safe: read, inspect, and arrange operations. Arbitrary
Lua evaluation exists as hs_eval, but it is off unless you set
HS_MCP_TOOLS=all.
See Security for the reasoning. Short version: the threat is prompt injection, not you.
Most of the value of Hammerspoon is your own init.lua. So the server helps you
write it, not just drive it:
hs_api_search searches Hammerspoon's bundled API documentation, so the agent
can look up the real signature of hs.window.moveToUnit instead of guessing.hs_console_tail reads back the Hammerspoon console, so the agent can see its
own errors.hs_reload_config reloads init.lua after an edit.Edit, reload, read the console, fix. The agent can run that loop itself.
macOS.
Node.js 24 or newer.
Hammerspoon, installed and running:
The hs.ipc module loaded in your Hammerspoon config. Add this line to
~/.hammerspoon/init.lua:
Then reload your config from the Hammerspoon menu bar icon. This is what
installs and enables the hs command line tool. Without it, hs -c has
nothing to talk to.
Verify the bridge by hand before wiring up any client:
If that prints 2, you are ready.
Claude Code:
Any client that takes an mcpServers JSON block:
To opt into the unsafe tier, add the environment variable. Claude Code:
JSON:
Ask the agent to call hs_health first. It reports whether the hs binary was
found, whether Hammerspoon is running, and whether hs.ipc answered.
Forty-one tools: thirty-eight in the safe tier, three gated.
No reviews yet โ be the first to share how this listing worked for you.
Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/hammerspoon-mcp)<a href="https://allmcps.com/mcp/hammerspoon-mcp"><img src="https://allmcps.com/api/badge/hammerspoon-mcp?style=directory" alt="Hammerspoon MCP on AllMCPs" /></a>